复习日
仔细回顾一下之前14天的内容
尝试找到一个kaggle或者其他地方的结构化数据集,用之前的内容完成一个全新的项目,这样你也是独立完成了一个专属于自己的项目
要求:
1.有数据地址的提供数据地址,没有地址的上传网盘贴出地址即可。
2.尽可能与他人不同,优先选择本专业相关数据集
3.探索一下开源数据的网站有哪些?
数据地址:
中国空气污染 - Heywhale.comhttps://www.heywhale.com/mw/dataset/67f13657ae7aa2e45cd48197
数据说明:
此数据集包含来自中国五个主要城市(北京、上海、广州、成都和深圳)的合成但真实的空气污染数据。它从 2015 年到 2025 年,提供有关空气质量、气象条件和污染水平的宝贵信息。该数据集由 3000 行 24 列组成,涵盖了各种空气污染物、天气状况和地理细节。
该数据集专为数据分析、机器学习模型和空气质量预测应用程序而设计。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
from sklearn.model_selection import train_test_split
from imblearn.over_sampling import SMOTE
import xgboost as xgb
import lightgbm as lgb
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.metrics import classification_report, confusion_matrix
import shap
warnings.filterwarnings("ignore")
# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows 系统常用黑体字体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
# 设置图片清晰度
plt.rcParams['figure.dpi'] = 300
def evaluate_model(model, X_test, y_test):
"""
评估模型的性能,打印分类报告、混淆矩阵和评估指标
"""
pred = model.predict(X_test)
print("\n分类报告:")
print(classification_report(y_test, pred))
print("混淆矩阵:")
print(confusion_matrix(y_test, pred))
accuracy = accuracy_score(y_test, pred)
precision = precision_score(y_test, pred)
recall = recall_score(y_test, pred)
f1 = f1_score(y_test, pred)
print("模型评估指标:")
print(f"准确率: {accuracy:.4f}")
print(f"精确率: {precision:.4f}")
print(f"召回率: {recall:.4f}")
print(f"F1 值: {f1:.4f}")
# 读取数据
data = pd.read_csv("E:\shucai\air_pollution_china.csv")
# 删除无关列(如时间戳,若不需要时间特征)
# 这里没有时间戳列,所以此步骤可略过
# 处理缺失值
data = data.dropna()
# 提取特征和目标变量
X = data.drop(columns=['AQI'])
y = data['AQI']
# 对非数值型特征进行编码
X = pd.get_dummies(X, columns=['Season', 'City', 'Day of Week', 'Weather Condition'])
# 查看y中各个类别的样本数量
class_counts = y.value_counts()
# 获取样本数量大于等于2的类别
valid_classes = class_counts[class_counts >= 2].index
# 保留有效类别的样本
valid_indices = y.isin(valid_classes)
X = X[valid_indices]
y = y[valid_indices]
# 计算连续特征的相关系数矩阵(包含所有数值特征)
continuous_cols = X.select_dtypes(include=np.number).columns.tolist()
correlation_matrix = X[continuous_cols].corr()
# 绘制热力图
plt.figure(figsize=(30, 20))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('连续特征相关性热力图')
plt.show()
# 划分训练集和测试集(20%作为测试集)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y # 分层抽样保持类别平衡
)
# 打印数据集形状
print(f"训练集形状: {X_train.shape}, 测试集形状: {X_test.shape}")
# ------------------------- 随机森林模型 -------------------------
rf_model = RandomForestClassifier(random_state=42, n_estimators=100, n_jobs=-1)
rf_model.fit(X_train, y_train)
evaluate_model(rf_model, X_test, y_test)
# ------------------------- XGBoost 模型 -------------------------
xgb_model = xgb.XGBClassifier(random_state=42, n_estimators=100, learning_rate=0.1)
xgb_model.fit(X_train, y_train)
evaluate_model(xgb_model, X_test, y_test)
# ------------------------- LightGBM 模型 -------------------------
lgb_model = lgb.LGBMClassifier(random_state=42, n_estimators=100, n_jobs=-1)
lgb_model.fit(X_train, y_train)
evaluate_model(lgb_model, X_test, y_test)
# 检查每个类别的样本数量
class_counts = y_train.value_counts()
if (class_counts < 2).any():
print("存在样本数量少于 2 的类别,跳过 SMOTE 过采样步骤。")
X_train_smote, y_train_smote = X_train, y_train
else:
# ------------------------- SMOTE 过采样处理 -------------------------
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
print("\nSMOTE 过采样后训练集形状:", X_train_smote.shape, y_train_smote.shape)
# 训练过采样后的 XGBoost 模型
xgb_model_smote = xgb.XGBClassifier(random_state=42, n_estimators=100)
xgb_model_smote.fit(X_train_smote, y_train_smote)
evaluate_model(xgb_model_smote, X_test, y_test)
explainer = shap.TreeExplainer(xgb_model)
shap_values = explainer.shap_values(X_test)
# 检查 shap_values 的类型
if isinstance(shap_values, list):
# 如果是列表,通常表示[负类 SHAP 值, 正类 SHAP 值]
if len(shap_values) == 2:
shap_values_positive = shap_values[1] # 正类的 SHAP 值
else:
shap_values_positive = shap_values[0] # 只有一个类别,直接使用
else:
# 如果不是列表,直接使用
shap_values_positive = shap_values
# 确保 shap_values 是二维数组
if len(shap_values_positive.shape) == 1:
shap_values_positive = shap_values_positive.reshape(-1, 1)
# 条形图:特征重要性(基于 SHAP 值绝对值均值)
shap.summary_plot(
shap_values_positive,
X_test,
feature_names=X_test.columns.tolist(),
plot_type="bar",
color=plt.get_cmap("viridis")(np.linspace(0, 1, len(X_test.columns))),
title="特征重要性(SHAP 值)"
)
plt.show()
# 蜂群图:特征影响分布
shap.summary_plot(
shap_values_positive,
X_test,
feature_names=X_test.columns.tolist(),
title="特征对正类预测的影响分布",
plot_size=(8, 6)
)
plt.show()