Kaggle竞赛——心脏病患者预测与可视化

news2024/12/23 14:27:03

目录

  • 准备工作
  • 1. 特征解释
  • 2. 生成探索性数据分析报告
    • 2.1 数据集导入
    • 2.2 生成数据分析报告
  • 3. 可视化分析
    • 3.1 特征相关性分析
    • 3.2 患病人数统计
    • 3.3 特征与是否患病之间的关系
  • 4. 数据处理
    • 4.1 定类数据处理
    • 4.2 独热编码
  • 5. 模型搭建
    • 5.1 随机森林模型
    • 5.2 可视化决策树
    • 5.3 特征重要性分析
    • 5.4 模型测试
    • 5.5 混淆矩阵与ROC曲线
  • 6. pdpbox数据可视化分析
    • 6.1 先验分析
    • 6.2 部分依赖图
      • 6.2.1 单变量PDP图
      • 6.2.2 二维PDP图
    • 6.3 ICE曲线
  • 7. shap模型可解释性分析
    • 7.1 计算shap值
    • 7.2 特征重要性
    • 7.3 可视化
      • 7.3.1 shap值图
      • 7.3.2 特征交互图
    • 7.4 单样本预测的解释可视化
    • 7.5 多样本预测的解释可视化
    • 7.6 shap依赖图
    • 7.7 部分依赖图
    • 7.8 决策图
    • 7.9 分析被错误分类的样本
    • 7.10 样本的特征交互关系
    • 7.11 单个样本分析
    • 7.12 单个特征分析

Kaggle中已经没有对应的比赛,所以只能从数据集中划分出测试集以验证模型的准确率。模型仅使用随机森林,本文侧重点在于数据分析的可视化和模型可解释性分析。所使用的python虚拟环境、数据集和代码已打包上传到Gitee,『点击直达』。
参考资料:【子豪兄Kaggle】玩转UCI心脏病二分类数据集

准备工作

打包环境,生成依赖文件

# 不用先激活环境,通过 --name-- 后的参数指定即可
conda env export --name kaggle --file D:\env\environment.yml
# 需要先激活环境
conda env export > D:\env\environment.yml

从依赖文件中创建环境

conda env create --file environment.yml

在 Jupyter Notebook 中添加虚拟环境

  1. 激活环境:conda activate kaggle
  2. 安装 ipykernel:conda install ipykernel
  3. 将环境添加为 Jupyter 内核: python -m ipykernel install --user --name kaggle --display-name "kaggle"
  4. 选择内核:在 Jupyter Notebook 顶部菜单栏 “Kernel” 的 “Change kernel” 中选择已添加的环境。

1. 特征解释

数据集特征解释:

特征描述数值表示
age年龄
sex性别0=女;1=男
cp心绞痛病史0=典型心绞痛 ;1=非典型心绞痛;2=无心绞痛;3=无症状
trestbps静息血压
chol胆固醇含量
fbs空腹时是否血糖高0=否;1=是
restecg静息时的心电图特征0=正常;1=ST-T波有异常;2=根据Estes准则,有潜在的左心室肥厚
thalach最大心率
exang运动是否会导致心绞痛0=否;1=是
oldpeak相对于休息,运动引起的 ST 段抑制
slope心电图种ST波峰值的坡度0=上升;1=平坦;2=下降
ca心脏周边大血管的个数
thal是否患地中海贫血症0=未知;1=正常;2=固定缺陷;3=可逆缺陷
target标签列,是否患心脏病0=否;1=是

官网特征解释见『Heart Disease』。

2. 生成探索性数据分析报告

安装pandas_profiling模块,安装之后使用import ydata_profiling进行导入(模块名 pandas_profiling 在 2023.4.1 被弃用)。生成的探索性数据分析(EDA)报告包含特征分析、缺失值分析、数据分布、相关性分析、重复行分析

pip install pandas_profiling

2.1 数据集导入

import pandas as pd
import numpy as np
import ydata_profiling
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

data = pd.read_csv("D:/Desktop/kaggle数据集/heart-disease/heart-disease.csv")
data.head()

2.2 生成数据分析报告

profile = ydata_profiling.ProfileReport(data)
profile
# 将报告以html网页形式保存
profile.to_file("D:/Desktop/profile.html")

数据集分析概览:
在这里插入图片描述
特征分析:
在这里插入图片描述

3. 可视化分析

3.1 特征相关性分析

#-----------------------------------------------------------------------------------------------------#
# 特征相关性分析
# corr(): 各列之间的相关性矩阵
# annot=True: 显示数值
# square=True: 单元格设置为正方形
# fmt=".1f": 数值保留小数点后一位
#-----------------------------------------------------------------------------------------------------#
plt.figure(figsize=(20,10))
sns.heatmap(data.corr(), annot=True, square=True, fmt=".1f");

在这里插入图片描述

3.2 患病人数统计

# 统计患病与不患病的人数
sns.countplot(x='target', data=data);

在这里插入图片描述

3.3 特征与是否患病之间的关系

年龄与是否患病之间的关系:

#-----------------------------------------------------------------------------------------------------#
# crosstab(data.age, data.target): 创建交叉表,横轴为age,纵轴为target
#-----------------------------------------------------------------------------------------------------#
pd.crosstab(data.age, data.target).plot(kind='bar', figsize=(20, 6))
plt.xlabel("Age")
plt.ylabel("Count");

在这里插入图片描述
可以发现,患病的年龄集中在 29-54 岁之间。


不同性别,患心脏病与不患心脏病的分布情况:

pd.crosstab(data.sex, data.target).plot(kind='bar', figsize=(15,6))
# 标签水平显示
plt.xticks(rotation=0)
plt.legend(['Not Disease','Disease'])
plt.xlabel("Sex(0 = Female, 1=Male)")
plt.ylabel("Count");

在这里插入图片描述
由图可知, 女性患心脏病的比例更高。


不同年龄段,不同最大心率,患心脏病与不患心脏病患者的散点分布:

plt.scatter(x=data.age[data.target==1], y=data.thalach[data.target==1], c='red', label="Disease")
plt.scatter(x=data.age[data.target==0], y=data.thalach[data.target==0], c='blue', label="Not Disease")
plt.legend()
plt.xlabel("Age")
plt.ylabel("Maxium Heart Rate");

在这里插入图片描述
由图可知, 最大心率越高,患病的概率越大,患病的年龄集中在 29-54 岁之间。

4. 数据处理

4.1 定类数据处理

数据集中的特征可分为定类、定序、定距、定比四种,区别如下:

特征类型描述举例运算
定类(Norminal)离散值(不可排序)颜色、性别(可以是字符串或者数值)仅可判断是否相等
定序(Ordinal)离散值(可排序)满意度评分、学历定类运算+排序
定距(Interval)连续值(无绝对零点)温度(零度并不代表无温度)、年份(“0”并不表示无年份)定序运算+加减
定比(Ratio)连续纸(有绝对零点)身高、体重,血压定距运算+乘除

在pandas种,离散的定类特征列应该是object类型;连续的定距和定比特征应该是int64或者float64类型


需要将数据集中的定类数据由整数编码转为实际的字符串:

data['sex'][data['sex'] == 0] = 'female'
data['sex'][data['sex'] == 1] = 'male'

data['cp'][data['cp'] == 0] = 'typical angina'
data['cp'][data['cp'] == 1] = 'atypical angina'
data['cp'][data['cp'] == 2] = 'non-anginal pain'
data['cp'][data['cp'] == 3] = 'asymptomatic'

data['fbs'][data['fbs'] == 0] = 'lower than 120mg/ml'
data['fbs'][data['fbs'] == 1] = 'greater than 120mg/ml'

data['restecg'][data['restecg'] == 0] = 'normal'
data['restecg'][data['restecg'] == 1] = 'having ST-T wave abnormality'
data['restecg'][data['restecg'] == 2] = 'left ventricular hypertrophy'

data['exang'][data['exang'] == 0] = 'no'
data['exang'][data['exang'] == 1] = 'yes'

data['slope'][data['slope'] == 0] = 'upsloping'
data['slope'][data['slope'] == 1] = 'flat'
data['slope'][data['slope'] == 2] = 'downsloping'

data['thal'][data['thal'] == 0] = 'unknown'
data['thal'][data['thal'] == 1] = 'normal'
data['thal'][data['thal'] == 2] = 'fixed defect'
data['thal'][data['thal'] == 3] = 'reversable defect'

4.2 独热编码

# 独热编码
dum_data = pd.get_dummies(data)

将定类的数据先还原之后再用独热编码的好处:很多机器学习模型(如线性回归、逻辑回归等)会对数值型定类数据进行线性假设。如果直接使用序数编码,模型可能会认为 3 比 2 和 1 更大,从而在拟合过程中引入错误的线性关系。这种情况下,需要先将整数值还原回原始的分类标签,再进行独热编码。独热编码之后每个类别都被转换为独立的特征(类型为bool),模型不会再对bool值进行错误的线性假设。

5. 模型搭建

5.1 随机森林模型

# 划分数据集和标签
y = dum_data['target']
X = dum_data.drop('target', axis=1)

# 划分训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1)
print(f"训练集大小{X_train.shape}")
print(f"训练集大小{X_test.shape}")
训练集大小(242, 26)
训练集大小(61, 26)
# 模型搭建
from sklearn.ensemble import RandomForestClassifier

# random_state=100: 在相同的数据和参数下,模型的训练结果(例如生成的决策树、特征重要性、模型性能等)每次运行都相同
model = RandomForestClassifier(max_depth=5, n_estimators=100, random_state=100)
model.fit(X_train, y_train)

5.2 可视化决策树

可视化随机森林中下标为7的决策树。需要在『官网』安装Graphviz(安装时勾选添加路径到环境变量)。

estimator = model.estimators_[7]
estimator
DecisionTreeClassifier(max_depth=5, max_features='auto', random_state=638252938)
feature_names = X_train.columns
y_train_str = y_train.astype("str")
y_train_str[y_train_str == '0'] = 'no disease'
y_train_str[y_train_str == '1'] = 'disease'
#-----------------------------------------------------------------------------------------------------#
# 可视化决策树
# out_file='tree.dot': 指定输出文件名为 tree.dot,该文件包含决策树的结构
# rounded=True: 使节点边角为圆角
# proportion=True: 显示每个节点的样本比例
# label='root': 为根节点添加标签(不使用该属性的话图会太小,看不清)
# precision=2: 数值保留两位小数
# filled=True: 根据类别使用不同的颜色填充节点
#-----------------------------------------------------------------------------------------------------#
from sklearn.tree import export_graphviz
export_graphviz(estimator, out_file='tree.dot', 
                           feature_names=feature_names,  
                           class_names=y_train_str.values,  
                           rounded=True, proportion=True,
                           label='root',
                           precision=2, filled=True)  

# 使用 Graphviz 的 dot 命令将 tree.dot 文件转换为 PNG 格式
# -Tpng: 指定输出格式为 PNG
# -o tree.png: 指定输出文件名为 tree.png
# -Gdpi=600: 设置输出图像的分辨率为 600 DPI
from subprocess import call
call(['dot', '-Tpng', 'tree.dot', '-o', 'tree.png', '-Gdpi=600'])

from IPython.display import Image
Image(filename='tree.png')

在这里插入图片描述

5.3 特征重要性分析

feature_names = X_test.columns
feature_importances = model.feature_importances_
# np.argsort: 返回数组中元素从小到大的索引
# [::-1]: 反转数组,即从大到小
indices = np.argsort(feature_importances)[::-1]

for index in indices:
    print("feature %s (%f)"%(feature_names[index], feature_importances[index]))
feature cp_typical angina (0.142222)
feature thalach (0.122956)
feature oldpeak (0.108774)
...

5.4 模型测试

定性结果

y_pred = model.predict(X_test)
y_pred
array([0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0,
       1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0,
       0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0], dtype=int64)

定量结果

#定量分类(不患心脏病与患心脏病的置信度)
y_proba = model.predict_proba(X_test)
y_proba
array([[0.81317679, 0.18682321],
       [0.2447506 , 0.7552494 ],
       ...])

5.5 混淆矩阵与ROC曲线

相关概念:

TP(真阳性):实际为正例且被正确预测为正例的样本数
FP(假阳性):实际为反例但被错误预测为正例的样本数
FN(假阴性):实际为正例但被错误预测为反例的样本数
TN(真阴性):实际为反例且被正确预测为反例的样本数

在这里插入图片描述


真阳性率:
T P R = T P T P + F N TPR=\frac{TP}{TP+FN} TPR=TP+FNTP
假阳性率:
F P R = F P F P + T N FPR=\frac{FP}{FP+TN} FPR=FP+TNFP
精确率(查准率):
P r e c i s i o n = T P T P + F P Precision=\frac{TP}{TP+FP} Precision=TP+FPTP
召回率(查全率):
R e c a l l = T P T P + F N Recall=\frac{TP}{TP+FN} Recall=TP+FNTP
精确率和召回率的调和平均值:
F 1 − s c o r e = 2 ∗ P r e c i s i o n ∗ R e c a l l P r e c i s i o n + R e c a l l F1-score=\frac{2*Precision*Recall}{Precision+Recall} F1score=Precision+Recall2PrecisionRecall
真阳性率、查准率、召回率、F1-score和ROC面积与分类效果正相关,假阳性率与其负相关。
ROC曲线:横轴是假阳性率(FPR),纵轴是真阳性率(TPR)。ROC曲线关注的是真阳性率和假阳性率之间的平衡,即模型在不同阈值下正确分类正例和负例的能力。曲线所围面积越大,模型的分类性能越好。
AUC(Area Under the Curve):ROC 曲线下的面积,用于衡量模型的整体性能。AUC 值越接近 1,模型性能越好。


通过混淆矩阵分析定性结果:

#-----------------------------------------------------------------------------------------------------#
# 行为真实标签,列为预测标签,标签顺序为[0,1]
# 例如第二行第一列的4,表示实际为1(患病),预测为0(不患病)
#-----------------------------------------------------------------------------------------------------#
from sklearn.metrics import confusion_matrix
confusion = confusion_matrix(y_test, y_pred,labels=[0,1])
confusion
array([[21,  9],
       [ 4, 27]], dtype=int64)

通过ROC曲线(受试者工作特征曲线)分析定量结果:

#-----------------------------------------------------------------------------------------------------#
# y_test: 真实标签
# y_pred_quant: 每个样本属于正类的预测概率(置信度)
# thresholds: 阈值
#-----------------------------------------------------------------------------------------------------#
from sklearn.metrics import roc_curve, auc
y_pred_quant = y_proba[:,1]
fpr, tpr, thresholds = roc_curve(y_test, y_pred_quant)
print("fpr:\n", fpr)
print("tpr:\n", tpr)
print("thresholds:\n", thresholds)
 [0.         0.         0.         0.06666667 0.06666667 0.1
 0.1        0.16666667 0.16666667 0.2        0.2        0.23333333
 0.23333333 0.26666667 0.26666667 0.3        0.3        0.46666667
 0.46666667 0.6        0.6        1.        ]
tpr:
 [0.         0.03225806 0.35483871 0.35483871 0.4516129  0.4516129
 0.61290323 0.61290323 0.64516129 0.64516129 0.70967742 0.70967742
 0.74193548 0.74193548 0.80645161 0.80645161 0.90322581 0.90322581
 0.96774194 0.96774194 1.         1.        ]
thresholds:
 [1.96089603 0.96089603 0.88384259 0.87940765 0.82902295 0.82220243
 0.71001001 0.69203148 0.65818888 0.6507687  0.63753046 0.63498126
 0.63098892 0.62282083 0.59854867 0.57898037 0.45385261 0.39956627
 0.22940531 0.14913866 0.11592048 0.00841077]

这里的阈值并不是取自预测的概率值。
绘制ROC曲线:

# 绘制roc曲线,对角线是基线,即模型随机猜测的性能(随机猜测时,样本被分为正例和反例的概率相同,即FPR和TPR相同)
plt.plot(fpr, tpr)
plt.plot([0,1], [0, 1], ls="--", c=".3")
plt.title("ROC curve")
plt.xlabel("FPR(1 - Specificity)")
plt.ylabel("TPR")
plt.grid(True)

在这里插入图片描述

6. pdpbox数据可视化分析

使用pdpbox工具包分析数据,需要安装 0.2.0 版本才行(默认会安装 0.3.0 版本,该版本更新了一些函数用法,容易报错!)。『pdpbox官方文档』

pip install pdpbox==0.2.0 -i https://pypi.tuna.tsinghua.edu.cn/simple 

6.1 先验分析

根据数据的原始分布对特征中不同类别的患病概率进行先验分析,并分析特征之间的相互影响关系。
不同性别下患病的比例:

from pdpbox import pdp, get_dataset, info_plots

# summary_df: 数据统计信息
fig,axes, summary_df = info_plots.target_plot(
    df = dum_data, feature = 'sex_male', feature_name='sex', target='target'
)
_ = axes['bar_ax'].set_xticklabels(['Female', 'Male'])

在这里插入图片描述
不同最大心率下患病的比例:

fig, axes, summary_df = info_plots.target_plot(
    df = dum_data, feature = 'thalach', feature_name='maximum heart rate', target='target'
)

在这里插入图片描述
由图可知,最大心率越大,患心脏病的比例越高。


年龄与最大心率之间的影响关系:

feat_name1 = 'age'
feat_name2 = 'thalach'
nick_name1 = 'age'
nick_name2 = 'maximum heart rate'

fig, axes, summary_df = info_plots.target_plot_interact(
    df = dum_data, features = [feat_name1, feat_name2], feature_names=[nick_name1, nick_name2], target='target'
)

在这里插入图片描述
由图可知,在低年龄段(29-51),最大心率越大,患心脏病的概率越大,在高年龄段则没有联系。

6.2 部分依赖图

部分依赖图(Partial Dependence Plot,PDP)显示了一个或两个特征对模型预测结果的边际影响,部分依赖图可以显示目标和特征之间的关系是线性的、单调的还是更复杂的。PDP反映了某一特征在不同值变化时对模型预测结果的影响,PDP图是ICE曲线的平均

6.2.1 单变量PDP图

对性别特征的分析:

# 单变量PDP图(反映了某一特征在不同值变化时对模型预测结果的影响)
fig, axes, summary_df = info_plots.actual_plot(
    model = model, X=X_train, feature='sex_male', feature_name='gender', predict_kwds={}
)

在这里插入图片描述
由图可知,当样本的性别由女性变为男性时,患心脏病的概率会降低。这与先验分析基本一致,但是不能以先验分布作为结论,训练得到的模型绘制的数据分布才能作为结论。

对"thalach"(最大心率)特征的分析:

fig, axes, summary_df = info_plots.actual_plot(
    model = model, X=X_train, feature='thalach', feature_name='maxium_heart_rate', predict_kwds={}
)

在这里插入图片描述由图可知,与先验分析基本吻合。

PDP图的另一种画法:

pdp_dist = pdp.pdp_isolate(
    model=model, dataset=X_test, model_features=base_features, feature="thalach"
)
fig, axes = pdp.pdp_plot(pdp_dist, "maxium_heart_rate")

在这里插入图片描述

6.2.2 二维PDP图

最大心率与大血管数的二维PDP图:

# 出现ypeError: clabel() got an unexpected keyword argument 'contour_label_fontsize'报错,
# 由图可知,血管越多,最大心率越小,患病的概率越小;血管越少,最大心率越大,患病的概率越大
inter1 = pdp.pdp_interact(
    model = model, dataset=X_test, model_features=base_features, features=['thalach', 'ca']
)
fig, axes = pdp.pdp_interact_plot(
    pdp_interact_out=inter1, feature_names=['maxium_heart_rate','num_vessels'], plot_type='contour'
)

运行代码时会出现报错:

ypeError: clabel() got an unexpected keyword argument 'contour_label_fontsize'

需将D:\Program Files (x86)\anaconda3\envs\kaggle\Lib\site-packages\pdpbox\pdp_plot_utils.py中的

inter_ax.clabel(c2, contour_label_fontsize=fontsize, inline=1)

改为

inter_ax.clabel(c2, fontsize=fontsize, inline=1)

运行结果:
在这里插入图片描述

slope_flat 和 oldpeak 的二维PDP图:

inter1 = pdp.pdp_interact(
    model = model, dataset=X_test, model_features=base_features, features=['slope_flat', 'oldpeak']
)
fig, axes = pdp.pdp_interact_plot(
    pdp_interact_out=inter1, feature_names=['slope_flat','oldpeak'], plot_type='contour'
)

在这里插入图片描述

6.3 ICE曲线

ICE(Individual Conditional Expectation,个体条件期望)曲线通过展示单个实例中指定特征变化时预测目标如何变化,‌来提供模型预测的局部解释。‌与PDP不同,‌PDP显示的是特征的平均影响,‌而ICE则关注于单个实例,‌提供更细致的预测变化分析。‌ICE曲线的数量与样本数量相同,‌每条曲线代表一个样本的预测变化,‌从而揭示了模型预测的异质关系。‌

性别特征的ICE曲线:

#-----------------------------------------------------------------------------------------------------#
# 绘制ICE曲线(将测试集中每个样本的pdp图单独绘制出来)
#-----------------------------------------------------------------------------------------------------#
base_features = dum_data.columns.values.tolist()
base_features.remove("target")
pdp_dist = pdp.pdp_isolate(
    model=model, dataset=X_test, model_features=base_features, feature="sex_male"
)
# plot_pts_dist为True时会报错,绘制不了数据点的分布情况
fig, axes = pdp.pdp_plot(pdp_dist, "gender", plot_lines=True, frac_to_plot=0.2, plot_pts_dist=False)

在这里插入图片描述
年龄特征的ICE曲线:

pdp_dist = pdp.pdp_isolate(
    model=model, dataset=X_test, model_features=base_features, feature="age"
)
fig, axes = pdp.pdp_plot(pdp_dist, "Age", plot_lines=True)

在这里插入图片描述

7. shap模型可解释性分析

Shapley值:是一种衡量每个特征对模型预测的边际贡献的方法,计算复杂度高,适合用于小规模数据和理论分析。
SHAP值:是基于Shapley值的实际实现,通过高效的近似算法能够在大规模数据和复杂模型中应用,提供统一的解释框架和丰富的可视化工具。
SHAP越大,代表该特征对模型预测的贡献越大,特征越重要。


shap工具包的直观作用如下图,机器学习模型通常都是黑盒,即对于给定的输入特征和模型预测输出结果,我们并不知道哪些特征对预测结果的影响最大或者特征对预测结果有哪些贡献(正向贡献或者负向贡献)。而shap工具包赋予机器学习模型可解释性,打破机器学习模型的黑盒,让我们清楚地知道特征是如何影响模型的预测结果。『shap官方文档』
在这里插入图片描述

7.1 计算shap值

计算测试集每个样本的每个特征对两类预测结果的shap值:

# 导入shap机器学习可解释性分析工具包
import shap
# 初始化绘图环境
shap.initjs()

explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)

61个样本,26个特征,对“患病”预测结果的shap值:

shap_values[1].shape
(61, 26)
shap_values[1]
array([[-0.01991538, -0.01593832,  0.00940888, ...,  0.00085783,
        -0.04006538,  0.00045913],
       [ 0.00745719,  0.00438513,  0.01242003, ...,  0.00164105,
        -0.05582202,  0.00023585],
       [ 0.00459926,  0.00017691, -0.01073604, ...,  0.00109371,
        -0.04040455,  0.00014795],
       ...,
       [ 0.03977282,  0.00520192,  0.00404147, ...,  0.00234018,
        -0.02645105,  0.00021561],
       [-0.0194963 , -0.00737674, -0.02220931, ..., -0.01112436,
         0.01327783,  0.00010092],
       [-0.02583896, -0.05348468, -0.02133602, ...,  0.00105833,
         0.02569354,  0.00020135]])
# 测试集中的所有样本,预测为“不患病”和“患病”各自的平均概率
expected_value = explainer.expected_value
expected_value
array([0.45190083, 0.54809917])

对某个样本,模型预测为“患病”的概率等于测试集“患病”的平均概率与该样本各特征对“患病”预测结果的shap值之和。

y_pred_proba_shap = shap_values[1].sum(axis=1)+explainer.expected_value[1]

该值与定量预测结果的第二列(患病概率)的值一致。

7.2 特征重要性

对于某个特征,计算测试集中所有样本的该特征的shap值之和(shap值越高特征越重要),即为该特征的重要性。

shap.summary_plot(shap_values[1], X_test, plot_type='bar')

在这里插入图片描述

7.3 可视化

7.3.1 shap值图

各特征的数值大小与shap值的关系图:

shap.summary_plot(shap_values[1], X_test)

在这里插入图片描述
图中每一行表示一个特征,红色表示该特征的值较高的数据点,蓝色值表示该特征的值较低的数据点。越靠右的点表示这个特征对预测为“患病”的正向影响越高(shap值越大),越靠左shap值越小(红蓝点能区分的情况下)。
由图可知,典型心绞痛(cp_typical angina)的值越大,shap值越小,对模型预测患病有负向贡献。最大心率(thalach)的值越大,shap值越大,对模型预测患病有正向贡献。


小提琴图展示数据分布情况:

shap.summary_plot(shap_values[1], X_test, plot_type='violin')

在这里插入图片描述

7.3.2 特征交互图

特征交互图(观察哪些特征组合对模型预测影响最大):

#-----------------------------------------------------------------------------------------------------#
# 对角线与上述关系图一致,其他两两特征之间没有明显的影响
# shap_interaction_values: 是一个矩阵,形状为 (样本数, 特征数, 特征数),其中每个元素表示两个特征的交互值
#-----------------------------------------------------------------------------------------------------#
shap_interaction_values = explainer.shap_interaction_values(X_test)
shap.summary_plot(shap_interaction_values[1], X_test)

在这里插入图片描述

7.4 单样本预测的解释可视化

取测试集中的第四个样本(在原始数据集上的索引为174),绘制“患病”预测结果的各特征的shap值:

idx = 174
patient = X.iloc[idx]
shap.summary_plot(shap_interaction_values[1][3], X_test, plot_type="bar")

df.loc[0:2, 'A']: 基于标签(行和列的名称),表示选择索引(并不一定是下标,例如Series中的索引可以无序)为 0 到 2 的行和标签为 'A’的列,返回一个Series 。
df.iloc[0:2, 0]:基于下标位置,选择第 0 和 1 行,第一列,返回一个Series。
df.loc[0:1]: 选择第 0 和 1 行,返回一个DataFrame。
df.iloc[0:1]: 选择第 0 行, 返回一个DataFrame。
注:df.iloc[0:2, :]等价于df.iloc[0:2];df.iloc[2, :]等价于df.iloc[2]。
在这里插入图片描述
绘制力导向图(各特征之间的贡献情况):

shap_values_patient = explainer.shap_values(patient)
shap.force_plot(explainer.expected_value[1], shap_values_patient[1], patient)

在这里插入图片描述红色表示正向贡献,蓝色表示负向贡献,越长表示shap值越高,即特征影响越大。红蓝条之间的长度差距即为base value(平均结果)到最终预测结果(f(x))之间的差距。

print('{}号病人是否患病 {} ,模型预测患病概率为 {:.2f}'.format(idx, bool(y_test[idx]), y_proba[3][1]))
174号病人是否患病 False ,模型预测患病概率为 0.02

绘制瀑布图(展示了某个病人从测试集平均结果到最终预测结果的决策过程,以及各特征对预测结果的贡献影响):

# 创建 Explanation 对象
# 注:data参数的值为DataFrame时会报错,为Series时不会报错。该参数可省略。
shap_values_exp = shap.Explanation(values=shap_values_patient[1], base_values=explainer.expected_value[1], data=patient)

# 绘制瀑布图
shap.waterfall_plot(shap_values_exp, max_display=15)

7.5 多样本预测的解释可视化

#-----------------------------------------------------------------------------------------------------#
# 多样本预测的解释可视化(将测试集所有样本的力导向图旋转九十度并拼接在一起)
# 可以在下拉菜单选择按照相似性聚类展示、按照预测结果概率从大到小展示、按照测试集原本样本顺序、按照某个特征分别展示
# 相似性排序:查看相似的病人都具有那些特征
#-----------------------------------------------------------------------------------------------------#
number_show = 60
shap_values_summary = explainer.shap_values(X_test.iloc[:number_show])
shap.force_plot(explainer.expected_value[1], shap_values_summary[1], X_test.iloc[:number_show])

在这里插入图片描述

7.6 shap依赖图

用于展示模型对于给定特征的依赖情况。

展示thalach特征从小变大时对预测结果为“患病”的shap值的变化情况:

shap.dependence_plot("thalach", shap_values[1], X_test, interaction_index=None)

在这里插入图片描述

7.7 部分依赖图

展示thalach特征从小变大时模型预测结果,纵轴表示实际预测结果(概率),两条虚线是均值。

shap.partial_dependence_plot("thalach", model.predict, X_test, model_expected_value=True, feature_expected_value=True)

在这里插入图片描述
由图可知,心率越大,预测的结果越大(患心脏病概率越大)。

7.8 决策图

瀑布图只能展示单个数据的决策过程,决策图可以展示测试集所有数据的决策过程。所有预测过程都从底部均值出发。

shap.decision_plot(expected_value[1], shap_values[1], X_test)

在这里插入图片描述
使用层次聚类(hierarchical clustering)来排列特征,以便更好地展示特征之间的关系:

# 查看典型决策路径,方便分析异常点
shap.decision_plot(expected_value[1], shap_values[1], X_test, feature_order='hclust')

在这里插入图片描述

7.9 分析被错误分类的样本

挑选出测试集中模型预测错误的样本,一共13个样本分类错误:

misclassified = y_pred != y_test
misclassified_df = misclassified[misclassified==True]
misclassified_df
278    True
302    True
228    True
150    True
189    True
95     True
138    True
182    True
283    True
188    True
299    True
259    True
110    True
Name: target, dtype: bool

选出278号病人详细分析:

mis_patient = X.iloc[278:279]
patient_proba = model.predict_proba(mis_patient)
print('{}号病人是否患病 {} ,模型预测患病概率为 {:.2f}'.format(278, bool(y_test[278]), patient_proba[0][1]))

shap_values_patient = explainer.shap_values(mis_patient)
shap.force_plot(explainer.expected_value[1],shap_values_patient[1], mis_patient)
278号病人是否患病 False ,模型预测患病概率为 0.88

在这里插入图片描述
在决策图中标记(点画线)出测试集中模型预测错误的样本:

# highlight=misclassified: 如果 misclassified 是布尔数组,数组中为 True 的位置对应的样本将被突出显示(点画线形式)
shap.decision_plot(expected_value[1], shap_values[1], highlight=misclassified)

在这里插入图片描述
只查看分类错误的样本:
在这里插入图片描述

7.10 样本的特征交互关系

绘制测试集中下标为5的样本的特征之间的交互关系:

plt.figure(figsize=(10, 10))
sns.heatmap(shap_interaction_values[1][5], annot=True, fmt=".1f", square=True);

在这里插入图片描述

7.11 单个样本分析

绘制25号病人某一特征变化时对模型分类结果的影响:

idx = 25
X_test.iloc[idx]
age                                      38.0
trestbps                                138.0
chol                                    175.0
thalach                                 173.0
oldpeak                                   0.0
ca                                        4.0
sex_female                                0.0
sex_male                                  1.0
cp_asymptomatic                           0.0
cp_atypical angina                        0.0
cp_non-anginal pain                       1.0
cp_typical angina                         0.0
fbs_greater than 120mg/ml                 0.0
fbs_lower than 120mg/ml                   1.0
restecg_having ST-T wave abnormality      1.0
restecg_left ventricular hypertrophy      0.0
restecg_normal                            0.0
exang_no                                  1.0
exang_yes                                 0.0
slope_downsloping                         1.0
slope_flat                                0.0
slope_upsloping                           0.0
thal_fixed defect                         1.0
thal_normal                               0.0
thal_reversable defect                    0.0
thal_unknown                              0.0
Name: 164, dtype: float64
# 选取最大心率特征
feature_selected ="thalach"

# 将数据集中最小心率和最大心率之间的长度分为200份
sep = 200
feature_selected_min = dum_data[feature_selected].min()
feature_selected_max = dum_data[feature_selected].max()

step = (feature_selected_max-feature_selected_min)/sep
rg = np.arange(feature_selected_min, feature_selected_max, step)

# 生成一个数组,其中 idx 被重复 200 次
# drop=True 表示不保留旧的索引列,而是创建一个新的默认整数索引
R = dum_data.iloc[np.repeat(idx, len(rg))].reset_index(drop=True)
R = R.drop("target", axis=1)
# 只改变选中列特征的值,其他特征不变
R[feature_selected] = rg

hypothetical_shap_values = explainer.shap_values(R)[1]
shap.dependence_plot(feature_selected, hypothetical_shap_values, R, interaction_index=None)

在这里插入图片描述
绘制25号病人thalach特征的决策图,选取3个样本(thalach特征值不同):

shap.decision_plot(expected_value[1], hypothetical_shap_values[[10, 100, 199]], X_test.iloc[idx])

在这里插入图片描述

7.12 单个特征分析

# 找出各样本在"ca特征下的shap值
shap_ca = shap_values[1][:, X_test.columns.get_loc("ca")]
# 找出最大值和最小值,由结果可知最小值的绝对值更大
shap_max = np.max(shap_ca)
shap_min = np.min(shap_ca)
print(f"最大值:{shap_max}, 最小值:{shap_min}")
最大值:0.08015789240556535, 最小值:-0.1500817362994171

找出全部测试集中ca特征对哪个样本的影响最大(shap绝对值最大),可以分析受影响较大的这一类人具有什么相同的特征:

max_imp = np.where(shap_old == shap_min)
print('{}号病人是否患病: {},模型预测患病概率为 {:.2f}'.format(max_imp[0][0], bool(y_test.iloc[58]), y_proba[58][1]))
33号病人是否患病: True,模型预测患病概率为 0.65

绘制该病人的瀑布图:

max_imp_patient = X_test.iloc[max_imp[0][0]]
shap_values_imp = explainer.shap_values(max_imp_patient)
# 创建 Explanation 对象
# 注:data参数的值为DataFrame时会报错,为Series时不会报错。该参数可省略。
exp_imp = shap.Explanation(values=shap_values_imp[1], base_values=explainer.expected_value[1], data=max_imp_patient)
# 绘制瀑布图
shap.waterfall_plot(exp_imp)

在这里插入图片描述
绘制决策图:

shap.decision_plot(expected_value[1], shap_values_imp[1], max_imp_patient)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2048266.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SourceTree基础使用教程

SourceTree基础使用 在B站上搜了不少关于SourceTree的教学视频,多家比较后下面的视频干活比较多 sourcetree使用教程 大概就二十几分钟,跟着学了一个小时,边看边操作,印象更深刻一些 主要涉及以下操作: 1、新建分支…

vue-echarts---折线图 (直接cv就行,全注释)

1、效果展示 2、完整代码&#xff0c;直接cv即可跑起来 <template><div id"mainend"></div> </template><script> import * as echarts from echarts; export default {name: LineChart,mounted() {this.initChart();this.registerUs…

NXP i.MX8系列平台开发讲解 - 4.1.1 GNSS篇(一) - 定位基础知识

专栏文章目录传送门&#xff1a;返回专栏目录 Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 文章目录 目录 专用名词&#xff1a; 1. GNSS 概述 1.2 四大GNSS 概述 1.2.1 GPS 1.2.2 BeiDou 1.2.3 GLONASS…

vue3 antdv3 将vxe-grid的头二行改为一行,解决最后一列不能自动根据屏幕的宽度自动缩放的问题。

1、先上个图&#xff1a; 官方地址&#xff1a; Vxe Table v4.6 header搞了二层&#xff0c;然后反馈过来&#xff0c;让调整&#xff1a; {title: 通讯地址,width: 200,showOverflow: tooltip,align: center,sortable: true,filters: companyOptions,filterRender: { name:…

国内首个支持国产化信创的开源云原生平台

国产化信创是指中国本土信息技术和创新产业的发展和推广。随着各种形势的复杂变化&#xff0c;推动国产化和信创已成为信息产业发展的重要方向。在这一背景下&#xff0c;国内的技术企业和开发者们纷纷投入到开源国产化和自主创新的浪潮中&#xff0c;力图摆脱对国外技术和服务…

谷歌开源Gemma-2 百亿参数大模型,性能超越Llama-3模型,免费使用

Gemma 模型 Gemma模型是谷歌发布的一个开源模型&#xff0c;任何人都可以免费下载预训练模型&#xff0c;进行使用。而谷歌最近也发布了Gemma 2 模型&#xff0c;模型参数超过了 200 亿大官&#xff0c;果真大模型最后都是拼参数的时候吗。 Gemma 2 模型发布 Gemma 2 模型可以…

【Linux系统编程】进程间的通信——管道通信

目录 前言&#xff1a; 一&#xff0c;管道的认识 二&#xff0c;管道的深入了解 2-1&#xff0c;管道的特点 2-2&#xff0c;深入学习管道 2-3&#xff0c;管道的特殊情况 三&#xff0c;匿名管道 四&#xff0c;Ubuntu系统和VSCode的使用 4-1&#xff0c;Ubuntu和VSC…

【ARM+Codesys 客户案例 】 基于RK3568/A40i/STM32+CODESYS在智能制造中的应用案例:全自动切片机器人

蔬菜是人们日常生活必不可缺的食品&#xff0c;并且食用方法多种多样。自步入小康社会以来&#xff0c;人们的生活节奏越来越快&#xff0c;很多传统服务已不能满足人们的物质需求和生活节奏。日常生活中通过手工快速切菜严重地威胁着人身安全&#xff0c;切菜时间过长或切菜不…

异常信息转储笔记-获取源码行号

前情 上一篇笔记《异常信息转储预研笔记-堆栈地址转换》留下了两个待解决问题&#xff08;如下图&#xff09;&#xff0c;问题1已在《异常信息转储笔记-demangle函数名字符》中解决&#xff0c;剩下问题2输出源码行号的问题还未能解决。 之前使用dladdr并未能将堆栈地址转换…

CourseGPT彻底改变本科学习

文章介绍了CourseGPT这一生成式AI工具&#xff0c;它基于Mistral AI的大型语言模型&#xff0c;旨在通过提供持续的教师支持和定期更新的课程材料来提升本科生的学习体验。CourseGPT能够利用课程特定的内容为学生提供精确和动态生成的回答&#xff0c;并且教师可以控制这些回答…

收藏:U盘加密软件哪个好用,防止U盘防复制软件

“物以稀为贵&#xff0c;藏之深则安。” 在信息时代的洪流中&#xff0c;数据之珍贵&#xff0c;无异于古时之金玉珠宝&#xff0c;而保护这些数据的安全&#xff0c;则成为了现代人心中的一道重要防线。 U盘&#xff0c;这小巧便携的数据存储工具&#xff0c;虽不及古时铜匣…

Jenkins-更新

文章目录 前言一、下载最新的war包二、安装最新的war包&#xff08;一&#xff09;查询Jenkins.war目录命令&#xff08;二&#xff09;切换到Jenkins.war的安装目录&#xff08;三&#xff09;上传最新Jenkins.war包 总结 前言 当我们在CentOS8 系统成功安装上Jenkins服务后&…

数据结构(6.2_1)——领接矩阵法

图的存储——邻接矩阵法 邻接矩阵&#xff08;Adjacency Matrix&#xff09;是一种使用二维数组来表示图的方法。在这种表示法中&#xff0c;矩阵的行和列都对应图的顶点。 特点 对于无向图&#xff0c;如果顶点i与顶点j之间有边&#xff0c;则矩阵的第i行第j列&#xff08;…

pytorch实现单层线性回归模型

文章目录 简述代码重构要点 数学模型、运行结果数据构建与分批模型封装运行测试 简述 python使用 数值微分法 求梯度&#xff0c;实现单层线性回归-CSDN博客 python使用 计算图&#xff08;forward与backward&#xff09; 求梯度&#xff0c;实现单层线性回归-CSDN博客 数值微分…

会议中控系统有多少种编程方法

会议中控系统的编程方法并不局限于某一种固定的方式&#xff0c;而是根据系统的具体需求、开发团队的技能以及所选用的编程语言和技术栈等多种因素来决定的。以下是一些常见的会议中控系统编程方法和考虑因素&#xff1a; 1. 编程语言选择 会议中控系统的开发通常会选择以下几…

Kubernetes拉取阿里云的私人镜像

前提条件 登录到阿里云控制台 拥有阿里云的ACR服务 创建一个命名空间 获取仓库的访问凭证&#xff08;可以设置固定密码&#xff09; 例如 sudo docker login --usernameyourAliyunAccount registry.cn-guangzhou.aliyuncs.com 在K8s集群中创建一个secret 使用kubectl命令行…

qt生成一幅纯马赛克图像

由于项目需要&#xff0c;需生成一幅纯马赛克的图像作为背景&#xff0c;经过多次测试成功&#xff0c;记录下来。 方法一&#xff1a;未优化方法 1、代码&#xff1a; #include <QImage> #include <QDebug> #include <QElapsedTimer>QImage generateMosa…

AI跟踪报道第52期-新加坡内哥谈技术-本周AI新闻: X推出的惊人逼真的但不受约束的图像生成器和 GooglePixel 9

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

PostgreSQL-02-入门篇-查询数据

文章目录 1 简单查询SELECT 语句简介SELECT 语句语法SELECT 示例1) 使用 SELECT 语句查询一列数据的示例2) 使用 SELECT 语句查询多列数据的示例3) 使用 SELECT 语句查询表所有列数据的示例4) 使用带有表达式的 SELECT 语句的示例5) 使用带有表达式的 SELECT 语句的示例 2 列别…

大公报发表欧科云链署名文章:发行港元稳定币,建Web3.0新生态

欧科云链研究院资深研究员蒋照生近日与香港科技大学副校长兼香港Web3.0协会首席科学顾问汪扬、零壹智库创始人兼CEO柏亮&#xff0c;在大公报发布联合署名文章 ——《Web3.0洞察 / 发行港元稳定币&#xff0c;建Web3.0新生态》&#xff0c;引发市场广泛讨论。 文章就香港稳定币…