Python 14-实验 集成模型综合应用-识别乳腺疾病

本 Notebook 按照 Word 实验报告要求完成,并优先参考 PDF 课本第 14 章的代码方法。

实验任务包括:

  1. 构建乳腺疾病识别的 AdaBoostClassifier 模型。
  2. 构建乳腺疾病识别的 GradientBoostingClassifier 模型。
  3. 构建乳腺疾病识别的 XGBClassifier 模型。

说明:Word 要求训练集和测试集比为 3:1,因此使用 test_size=0.25。PDF 课本使用的是信用卡违约或欺诈数据,与本实验数据不同,所以最终指标不会与课本数值完全一致。

import pandas as pd  # 导入 pandas 第三方包,用于读取和处理表格数据
import numpy as np  # 导入 numpy 第三方包,用于数组转换和数值计算
import matplotlib.pyplot as plt  # 导入 pyplot,用于绘制饼图、ROC 曲线和条形图
from sklearn import model_selection  # 从 sklearn 中导入 model_selection,用于拆分训练集和测试集
from sklearn import ensemble  # 从 sklearn 中导入 ensemble,用于构建 AdaBoost 和 GBDT 模型
from sklearn import metrics  # 从 sklearn 中导入 metrics,用于评估模型效果
import xgboost  # 导入 xgboost 第三方包,用于构建 XGBClassifier 模型
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 设置中文字体,避免图形中的中文乱码
plt.rcParams['axes.unicode_minus'] = False  # 设置坐标轴负号正常显示

一、读取数据与预处理

数据集第一列 type 为乳腺疾病种类,其中 Pathological 表示病理样本,Normal 表示正常样本。为了便于绘制 ROC 曲线并运行 XGBoost,将 Normal 映射为 0,将 Pathological 映射为 1。

breast = pd.read_csv(r'12-breast.csv')  # 读取 breast.csv 数据集
breast.columns = breast.columns.str.strip()  # 去除字段名两侧可能存在的空格
print(breast.head())  # 查看数据集前 5 行
print(breast.shape)  # 查看数据集的行数和列数
print(breast.type.value_counts())  # 统计不同乳腺疾病种类的样本数量
           type  impedance_zero  phase_angle  high_frequency_slope  \
0  Pathological          524.79         0.19                  0.03   
1  Pathological          330.00         0.23                  0.27   
2  Pathological          551.88         0.23                  0.06   
3  Pathological          380.00         0.24                  0.29   
4  Pathological          362.83         0.20                  0.24   

   impedance_distance  area_under_spectrum  area_normalized  max_spectrum  \
0              228.80              6843.60            29.91         60.20   
1              121.15              3163.24            26.11         69.72   
2              264.80             11888.39            44.89         77.79   
3              137.64              5402.17            39.25         88.76   
4              124.91              3290.46            26.34         69.39   

   distance  length  
0    220.74  556.83  
1     99.08  400.23  
2    253.79  656.77  
3    105.20  493.70  
4    103.87  424.80  
(106, 10)
type
Pathological    54
Normal          52
Name: count, dtype: int64
plt.axes(aspect='equal')  # 为确保饼图为圆形,设置坐标轴比例相等
counts = breast.type.value_counts()  # 统计 Pathological 和 Normal 的频数
plt.pie(x=counts, labels=pd.Series(counts.index).map({'Pathological':'病理', 'Normal':'正常'}), autopct='%.2f%%')  # 绘制样本类别比例饼图
plt.title('乳腺疾病类别比例')  # 添加图形标题
plt.show()  # 显示图形


png

X = breast.drop(['type'], axis=1)  # 删除因变量 type,剩余数据作为自变量 X
y = breast.type.map({'Normal':0, 'Pathological':1})  # 将类别标签数值化,其中 Normal 为 0,Pathological 为 1
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.25, random_state=1234)  # 按训练集和测试集 3:1 的比例拆分数据
print(y_train.value_counts()/len(y_train))  # 输出训练集中各类别所占比例
print(y_test.value_counts()/len(y_test))  # 输出测试集中各类别所占比例
type
1    0.531646
0    0.468354
Name: count, dtype: float64
type
0    0.555556
1    0.444444
Name: count, dtype: float64

二、任务一:构建 AdaBoostClassifier 模型

AdaBoost1 = ensemble.AdaBoostClassifier()  # 构建 AdaBoostClassifier 算法的类,参数保持课本默认写法
AdaBoost1.fit(X_train, y_train)  # 使用训练数据集拟合 AdaBoostClassifier 模型
pred1 = AdaBoost1.predict(X_test)  # 使用训练好的模型对测试数据集进行预测
print('模型的准确率为:')
print(metrics.accuracy_score(y_test, pred1))  # 输出 AdaBoostClassifier 模型的准确率
print('模型的评估报告:')
print(metrics.classification_report(y_test, pred1, target_names=['Normal', 'Pathological'], zero_division=0))  # 输出 AdaBoostClassifier 模型的分类评估报告
模型的准确率为:
0.8148148148148148
模型的评估报告:
              precision    recall  f1-score   support

      Normal       0.92      0.73      0.81        15
Pathological       0.73      0.92      0.81        12

    accuracy                           0.81        27
   macro avg       0.82      0.82      0.81        27
weighted avg       0.84      0.81      0.81        27
y_score1 = AdaBoost1.predict_proba(X_test)[:,1]  # 计算病理样本的概率值,用于生成 ROC 曲线的数据
fpr1, tpr1, threshold1 = metrics.roc_curve(y_test, y_score1)  # 计算 AdaBoostClassifier 模型的 FPR、TPR 和阈值
roc_auc1 = metrics.auc(fpr1, tpr1)  # 计算 AdaBoostClassifier 模型 ROC 曲线下的面积 AUC
plt.stackplot(fpr1, tpr1, color='steelblue', alpha=0.5, edgecolor='black')  # 按课本写法绘制 ROC 曲线下面积图
plt.plot(fpr1, tpr1, color='black', lw=1)  # 添加 ROC 曲线边界线
plt.plot([0,1], [0,1], color='red', linestyle='--')  # 添加随机分类器的对角线
plt.text(0.5, 0.3, 'ROC curve (area = %0.2f)' % roc_auc1)  # 在图中添加 AUC 数值文本
plt.xlabel('1-Specificity')  # 添加 x 轴标签
plt.ylabel('Sensitivity')  # 添加 y 轴标签
plt.title('AdaBoostClassifier 的 ROC 曲线')  # 添加图形标题
plt.show()  # 显示图形


png

importance = pd.Series(AdaBoost1.feature_importances_, index=X.columns)  # 将 AdaBoostClassifier 模型的自变量重要性转为 Series
importance.sort_values().plot(kind='barh')  # 按课本写法绘制自变量重要性的水平条形图
plt.title('AdaBoostClassifier 自变量重要性排序')  # 添加图形标题
plt.show()  # 显示图形


png

三、任务二:构建 GradientBoostingClassifier 模型

GBDT1 = ensemble.GradientBoostingClassifier()  # 构建 GradientBoostingClassifier 算法的类,参数保持课本默认写法
GBDT1.fit(X_train, y_train)  # 使用训练数据集拟合 GradientBoostingClassifier 模型
pred2 = GBDT1.predict(X_test)  # 使用训练好的模型对测试数据集进行预测
print('模型的准确率为:')
print(metrics.accuracy_score(y_test, pred2))  # 输出 GradientBoostingClassifier 模型的准确率
print('模型的评估报告:')
print(metrics.classification_report(y_test, pred2, target_names=['Normal', 'Pathological'], zero_division=0))  # 输出 GradientBoostingClassifier 模型的分类评估报告
模型的准确率为:
0.8148148148148148
模型的评估报告:
              precision    recall  f1-score   support

      Normal       0.92      0.73      0.81        15
Pathological       0.73      0.92      0.81        12

    accuracy                           0.81        27
   macro avg       0.82      0.82      0.81        27
weighted avg       0.84      0.81      0.81        27
y_score2 = GBDT1.predict_proba(X_test)[:,1]  # 计算病理样本的概率值,用于生成 ROC 曲线的数据
fpr2, tpr2, threshold2 = metrics.roc_curve(y_test, y_score2)  # 计算 GradientBoostingClassifier 模型的 FPR、TPR 和阈值
roc_auc2 = metrics.auc(fpr2, tpr2)  # 计算 GradientBoostingClassifier 模型 ROC 曲线下的面积 AUC
plt.stackplot(fpr2, tpr2, color='steelblue', alpha=0.5, edgecolor='black')  # 按课本写法绘制 ROC 曲线下面积图
plt.plot(fpr2, tpr2, color='black', lw=1)  # 添加 ROC 曲线边界线
plt.plot([0,1], [0,1], color='red', linestyle='--')  # 添加随机分类器的对角线
plt.text(0.5, 0.3, 'ROC curve (area = %0.2f)' % roc_auc2)  # 在图中添加 AUC 数值文本
plt.xlabel('1-Specificity')  # 添加 x 轴标签
plt.ylabel('Sensitivity')  # 添加 y 轴标签
plt.title('GradientBoostingClassifier 的 ROC 曲线')  # 添加图形标题
plt.show()  # 显示图形


png

四、任务三:构建 XGBClassifier 模型

XGBoost1 = xgboost.XGBClassifier(eval_metric='logloss')  # 构建 XGBClassifier 算法的类,保留默认参数并设置评估指标以适配当前版本
XGBoost1.fit(X_train, y_train)  # 使用训练数据集拟合 XGBClassifier 模型
pred3 = XGBoost1.predict(X_test)  # 使用训练好的模型对测试数据集进行预测
print('模型的准确率为:')
print(metrics.accuracy_score(y_test, pred3))  # 输出 XGBClassifier 模型的准确率
print('模型的评估报告:')
print(metrics.classification_report(y_test, pred3, target_names=['Normal', 'Pathological'], zero_division=0))  # 输出 XGBClassifier 模型的分类评估报告
模型的准确率为:
0.7777777777777778
模型的评估报告:
              precision    recall  f1-score   support

      Normal       0.85      0.73      0.79        15
Pathological       0.71      0.83      0.77        12

    accuracy                           0.78        27
   macro avg       0.78      0.78      0.78        27
weighted avg       0.79      0.78      0.78        27
y_score3 = XGBoost1.predict_proba(np.array(X_test))[:,1]  # 计算病理样本的概率值,用于生成 ROC 曲线的数据
fpr3, tpr3, threshold3 = metrics.roc_curve(y_test, y_score3)  # 计算 XGBClassifier 模型的 FPR、TPR 和阈值
roc_auc3 = metrics.auc(fpr3, tpr3)  # 计算 XGBClassifier 模型 ROC 曲线下的面积 AUC
plt.stackplot(fpr3, tpr3, color='steelblue', alpha=0.5, edgecolor='black')  # 按课本写法绘制 ROC 曲线下面积图
plt.plot(fpr3, tpr3, color='black', lw=1)  # 添加 ROC 曲线边界线
plt.plot([0,1], [0,1], color='red', linestyle='--')  # 添加随机分类器的对角线
plt.text(0.5, 0.3, 'ROC curve (area = %0.2f)' % roc_auc3)  # 在图中添加 AUC 数值文本
plt.xlabel('1-Specificity')  # 添加 x 轴标签
plt.ylabel('Sensitivity')  # 添加 y 轴标签
plt.title('XGBClassifier 的 ROC 曲线')  # 添加图形标题
plt.show()  # 显示图形


png

result = pd.DataFrame({'模型':['AdaBoostClassifier', 'GradientBoostingClassifier', 'XGBClassifier'], '准确率':[metrics.accuracy_score(y_test, pred1), metrics.accuracy_score(y_test, pred2), metrics.accuracy_score(y_test, pred3)], 'AUC':[roc_auc1, roc_auc2, roc_auc3]})  # 汇总三个模型的准确率和 AUC
result  # 显示模型对比结果

模型 准确率 AUC
0 AdaBoostClassifier 0.814815 0.925000
1 GradientBoostingClassifier 0.814815 0.944444
2 XGBClassifier 0.777778 0.802778

五、实验结果分析

从本次实验结果看,乳腺数据集中 PathologicalNormal 的样本比例约为 50.94% 和 49.06%,不存在 PDF 课本信用卡案例中严重类别不平衡的问题,因此未使用 SMOTE 处理。

本实验的结果与 PDF 课本示例结果不同,主要原因是:PDF 使用的是信用卡违约或信用卡欺诈数据集,而 Word 要求使用 breast.csv 乳腺疾病数据集;数据规模、字段含义、类别比例和训练测试拆分比例均不同,因此准确率、分类报告和 AUC 不可能与课本示例数值完全一致。

在当前训练测试拆分下,三个集成模型都能够完成乳腺疾病识别任务。医学识别场景中,病理样本的漏判风险更高,因此除了总体准确率,也应重点关注 Pathological 类别的 recall。

六、思考题

AdaBoostClassifier、GradientBoostingClassifier、XGBClassifier 都属于集成学习中的提升类算法,基本思想都是将多个弱学习器组合成一个更强的分类模型。

AdaBoostClassifier 通过提高上一轮被错分样本的权重,使后续弱分类器更加关注难分类样本。GradientBoostingClassifier 则从损失函数的负梯度方向逐步拟合残差,本质上是不断修正前一轮模型的误差。XGBClassifier 是对 GBDT 的工程化和算法层面改进,引入了正则化、二阶梯度信息、列采样、缺失值处理和更高效的计算机制。

三者的联系是都采用逐轮迭代、多个基学习器叠加的提升思想;区别在于 AdaBoost 主要调整样本权重,GBDT 主要拟合损失函数梯度,XGBoost 在 GBDT 基础上进一步优化目标函数、正则化和计算效率。