Scikit-Learn 对糖尿病数据集(回归任务)进行全面分析
文章目录
- 背景
- 数据集速览
- 分析方法
- 分析步骤
- 分析结果
- 不同模型的预测值 vs 真实值效果对比
- 残差图
- 特征重要性
- 预测值分布
- 不同模型评估明细
- 代码
背景
糖尿病数据集,442个样本,10个特征(年龄、血压等),目标为疾病进展值
该数据集为回归问题,需要使用回归分析方法进行分析
数据集速览
import pandas as pd
from sklearn.datasets import load_diabetesdiabetes = load_diabetes()# 将数据转换为 Pandas DataFrame 以便更好地查看
# features(特征)
df_features = pd.DataFrame(diabetes.data, columns=diabetes.feature_names)# target(目标变量)
df_target = pd.DataFrame(diabetes.target, columns=['target'])# 合并特征和目标变量为一个 DataFrame
df_diabetes = pd.concat([df_features, df_target], axis=1)print("--- 数据集简要概览 ---")
print(f"数据形状 (行, 列): {df_diabetes.shape}")
print("\n数据集特征名称:")
print(diabetes.feature_names)
print("\n目标变量描述:")
print(diabetes.DESCR.split('\n')[-3]) # 提取目标变量的简要描述print("\n--- 数据前5行预览 ---")
print(df_diabetes.head())print("\n--- 数据信息 (类型和非空值) ---")
print(df_diabetes.info())
--- 数据集简要概览 ---
数据形状 (行, 列): (442, 11)数据集特征名称:
['age', 'sex', 'bmi', 'bp', 's1', 's2', 's3', 's4', 's5', 's6']目标变量描述:
Bradley Efron, Trevor Hastie, Iain Johnstone and Robert Tibshirani (2004) "Least Angle Regression," Annals of Statistics (with discussion), 407-499.--- 数据前5行预览 ---age sex bmi bp s1 s2 s3 \
0 0.038076 0.050680 0.061696 0.021872 -0.044223 -0.034821 -0.043401
1 -0.001882 -0.044642 -0.051474 -0.026328 -0.008449 -0.019163 0.074412
2 0.085299 0.050680 0.044451 -0.005670 -0.045599 -0.034194 -0.032356
3 -0.089063 -0.044642 -0.011595 -0.036656 0.012191 0.024991 -0.036038
4 0.005383 -0.044642 -0.036385 0.021872 0.003935 0.015596 0.008142 s4 s5 s6 target
0 -0.002592 0.019907 -0.017646 151.0
1 -0.039493 -0.068332 -0.092204 75.0
2 -0.002592 0.002861 -0.025930 141.0
3 0.034309 0.022688 -0.009362 206.0
4 -0.002592 -0.031988 -0.046641 135.0 --- 数据信息 (类型和非空值) ---
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 442 entries, 0 to 441
Data columns (total 11 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 age 442 non-null float641 sex 442 non-null float642 bmi 442 non-null float643 bp 442 non-null float644 s1 442 non-null float645 s2 442 non-null float646 s3 442 non-null float647 s4 442 non-null float648 s5 442 non-null float649 s6 442 non-null float6410 target 442 non-null float64
dtypes: float64(11)
memory usage: 38.1 KB
None
这份数据集共有 10 个特征
它们都是经过预处理和标准化的浮点数值,具体含义如下:
1. age: 年龄(years)
2. sex: 性别
3. bmi: 身体质量指数(body mass index)
4. bp: 平均血压(average blood pressure)
5. s1: T-细胞(T-cells)
6. s2: 低密度脂蛋白(LDL)
7. s3: 高密度脂蛋白(HDL)
8. s4: 甲状腺刺激素(TSH)
9. s5: 血糖(blood sugar)
10. s6: 淋巴细胞(lymphocytes)
分析方法
- 线性回归
- K近邻(KNN)
- 决策树
- 支持向量机
- 随机森林
- 多层感知器(MLP)
- Lasso 回归
- Ridge 回归
- 梯度提升回归
- AdaBoost 回归
- Huber 回归
分析步骤
- 加载数据集
- 拆分训练集、测试集
- 数据预处理(标准化)
- 选择模型
- 模型训练(拟合)
- 测试模型效果
- 评估模型
分析结果
不同模型的预测值 vs 真实值效果对比
残差图
特征重要性
预测值分布
不同模型评估明细
--- 数据集概览 ---
数据形状: (442, 10)
特征名称: ['age', 'sex', 'bmi', 'bp', 's1', 's2', 's3', 's4', 's5', 's6']
目标变量名称: 糖尿病病程进展--- 数据划分结果 ---
训练集形状: (309, 10)
测试集形状: (133, 10)--- 正在对数据进行标准化处理 ------ 模型训练与评估 ------ 正在训练 线性回归 模型 ---
线性回归 模型的均方误差 (MSE): 2821.7510
线性回归 模型的 R^2 得分: 0.4773--- 正在训练 K近邻 (K-NN) 模型 ---
K近邻 (K-NN) 模型的均方误差 (MSE): 3277.7368
K近邻 (K-NN) 模型的 R^2 得分: 0.3928--- 正在训练 决策树 模型 ---
决策树 模型的均方误差 (MSE): 5686.6015
决策树 模型的 R^2 得分: -0.0534--- 正在训练 支持向量机 (SVR) 模型 ---
支持向量机 (SVR) 模型的均方误差 (MSE): 2822.7007
支持向量机 (SVR) 模型的 R^2 得分: 0.4771--- 正在训练 随机森林 模型 ---
随机森林 模型的均方误差 (MSE): 2859.3911
随机森林 模型的 R^2 得分: 0.4703--- 正在训练 多层感知器 (MLP) 模型 ---
/opt/anaconda3/lib/python3.13/site-packages/sklearn/neural_network/_multilayer_perceptron.py:691: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (20000) reached and the optimization hasn't converged yet.warnings.warn(
多层感知器 (MLP) 模型的均方误差 (MSE): 4791.4414
多层感知器 (MLP) 模型的 R^2 得分: 0.1124--- 正在训练 Lasso 回归 模型 ---
Lasso 回归 模型的均方误差 (MSE): 2817.0876
Lasso 回归 模型的 R^2 得分: 0.4782--- 正在训练 Ridge 回归 模型 ---
Ridge 回归 模型的均方误差 (MSE): 2819.9820
Ridge 回归 模型的 R^2 得分: 0.4776--- 正在训练 梯度提升回归 模型 ---
梯度提升回归 模型的均方误差 (MSE): 3083.3332
梯度提升回归 模型的 R^2 得分: 0.4288--- 正在训练 AdaBoost 回归 模型 ---
AdaBoost 回归 模型的均方误差 (MSE): 2874.6206
AdaBoost 回归 模型的 R^2 得分: 0.4675--- 正在训练 Huber 回归 模型 ---
Huber 回归 模型的均方误差 (MSE): 2828.7736
Huber 回归 模型的 R^2 得分: 0.4760所有模型的分析已完成。
代码
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.svm import SVR
from sklearn.linear_model import LinearRegression, Lasso, Ridge, HuberRegressor
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor, AdaBoostRegressor
from sklearn.neural_network import MLPRegressor
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np
import matplotlib.pyplot as plt# 设置 Matplotlib 字体以正确显示中文
plt.rcParams['font.sans-serif'] = ['SimHei', 'WenQuanYi Zen Hei', 'STHeiti', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False def perform_diabetes_analysis():"""使用 scikit-learn 对糖尿病数据集进行全面的分析。该函数包含数据加载、预处理、模型训练、评估和结果可视化。"""print("--- 正在加载糖尿病数据集 ---")diabetes = load_diabetes()X = diabetes.datay = diabetes.targetfeature_names = list(diabetes.feature_names)print("\n--- 数据集概览 ---")print(f"数据形状: {X.shape}")print(f"特征名称: {feature_names}")print(f"目标变量名称: {'糖尿病病程进展'}")X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)print("\n--- 数据划分结果 ---")print(f"训练集形状: {X_train.shape}")print(f"测试集形状: {X_test.shape}")print("\n--- 正在对数据进行标准化处理 ---")scaler = StandardScaler()X_train_scaled = scaler.fit_transform(X_train)X_test_scaled = scaler.transform(X_test)models = {"线性回归": LinearRegression(),"K近邻 (K-NN)": KNeighborsRegressor(n_neighbors=5),"决策树": DecisionTreeRegressor(random_state=42),"支持向量机 (SVR)": SVR(kernel='rbf', C=100),"随机森林": RandomForestRegressor(random_state=42),"多层感知器 (MLP)": MLPRegressor(random_state=42, max_iter=20000),"Lasso 回归": Lasso(alpha=0.1, max_iter=10000),"Ridge 回归": Ridge(alpha=1.0, max_iter=10000),"梯度提升回归": GradientBoostingRegressor(random_state=42),"AdaBoost 回归": AdaBoostRegressor(random_state=42),"Huber 回归": HuberRegressor(max_iter=10000)}predictions = {}feature_importances = {}print("\n--- 模型训练与评估 ---")for name, model in models.items():print(f"\n--- 正在训练 {name} 模型 ---")model.fit(X_train_scaled, y_train)y_pred = model.predict(X_test_scaled)mse = mean_squared_error(y_test, y_pred)r2 = r2_score(y_test, y_pred)print(f"{name} 模型的均方误差 (MSE): {mse:.4f}")print(f"{name} 模型的 R^2 得分: {r2:.4f}")predictions[name] = y_predif hasattr(model, 'feature_importances_'):feature_importances[name] = model.feature_importances_print("\n所有模型的分析已完成。")# --- 预测值 vs. 实际值可视化 ---print("\n--- 预测值 vs. 实际值散点图 ---")num_models = len(models)cols = 3rows = (num_models + cols - 1) // colsfig, axes = plt.subplots(rows, cols, figsize=(18, 6 * rows))axes = axes.flatten()for i, name in enumerate(models.keys()):ax = axes[i]y_pred = predictions[name]ax.scatter(y_test, y_pred, alpha=0.6, label='预测值')lims = [np.min([ax.get_xlim(), ax.get_ylim()]),np.max([ax.get_xlim(), ax.get_ylim()]),]ax.plot(lims, lims, 'k--', alpha=0.75, zorder=0, label='理想预测')ax.set_title(f'{name} - 预测值 vs. 实际值', fontsize=14)ax.set_xlabel('实际病程进展', fontsize=12)ax.set_ylabel('预测病程进展', fontsize=12)ax.legend()ax.grid(True)for j in range(num_models, len(axes)):axes[j].axis('off')plt.tight_layout()plt.show()# --- 残差图可视化 ---print("\n--- 残差图可视化 ---")fig, axes = plt.subplots(rows, cols, figsize=(18, 6 * rows))axes = axes.flatten()for i, name in enumerate(models.keys()):ax = axes[i]y_pred = predictions[name]residuals = y_test - y_predax.scatter(y_pred, residuals, alpha=0.6)ax.axhline(y=0, color='r', linestyle='--', linewidth=2)ax.set_title(f'{name} - 残差图', fontsize=14)ax.set_xlabel('预测值', fontsize=12)ax.set_ylabel('残差 (实际值 - 预测值)', fontsize=12)ax.grid(True)for j in range(num_models, len(axes)):axes[j].axis('off')plt.tight_layout()plt.show()# --- 特征重要性可视化 (仅限树模型) ---if feature_importances:print("\n--- 特征重要性可视化 ---")num_tree_models = len(feature_importances)rows_tree = (num_tree_models + cols - 1) // colsfig, axes = plt.subplots(rows_tree, cols, figsize=(18, 6 * rows_tree))axes = axes.flatten()for i, (name, importances) in enumerate(feature_importances.items()):ax = axes[i]sorted_indices = np.argsort(importances)[::-1]sorted_importances = importances[sorted_indices]sorted_feature_names = [feature_names[j] for j in sorted_indices]ax.barh(sorted_feature_names, sorted_importances, color='skyblue')ax.set_title(f'{name} - 特征重要性', fontsize=14)ax.set_xlabel('重要性', fontsize=12)ax.set_ylabel('特征', fontsize=12)ax.grid(axis='x')for j in range(num_tree_models, len(axes)):axes[j].axis('off')plt.tight_layout()plt.show()# --- 预测值分布图可视化 ---print("\n--- 预测值分布图 ---")fig, axes = plt.subplots(rows, cols, figsize=(18, 6 * rows))axes = axes.flatten()all_values = np.concatenate([y_test] + list(predictions.values()))bins = np.linspace(min(all_values), max(all_values), 50)for i, name in enumerate(models.keys()):ax = axes[i]y_pred = predictions[name]ax.hist(y_test, bins=bins, alpha=0.6, label='实际值', color='b', edgecolor='k')ax.hist(y_pred, bins=bins, alpha=0.6, label='预测值', color='r', edgecolor='k')ax.set_title(f'{name} - 分布图', fontsize=14)ax.set_xlabel('病程进展', fontsize=12)ax.set_ylabel('频率', fontsize=12)ax.legend()ax.grid(True)for j in range(num_models, len(axes)):axes[j].axis('off')plt.tight_layout()plt.show()if __name__ == "__main__":perform_diabetes_analysis()