从基础到进阶:优化SHAP力图,让样本解读更直观

机器学习关系型数据库云安全

picture.image

背景

在机器学习模型的解释过程中,SHAP力图(SHAP Force Plot)被广泛用于展示单样本各个特征对模型预测结果的贡献,然而,标准的SHAP力图有时可能难以直观地传达关键信息,尤其是在特征数量较多或特征值之间存在较大差异的情况下,为了让模型的解释更具可读性和准确性,我们有必要对SHAP力图进行优化

在本篇文章中,我们将详细探讨如何通过调整SHAP力图的显示阈值、特征标注和视觉呈现等方面来优化图表,使其更易于解读,通过这些优化,我们不仅能够突出最重要的特征,还可以减少信息冗余,从而帮助我们更清晰地理解模型的决策逻辑。这些优化步骤不仅提升了图表的美观性,还增强了它在实际应用中的实用性

代码实现

模型构建


          
import pandas as pd
          
import numpy as np
          
import matplotlib.pyplot as plt 
          
plt.rcParams['font.sans-serif'] = 'SimHei'
          
plt.rcParams['axes.unicode_minus'] = False
          
df = pd.read_excel('california.xlsx')
          

          
from sklearn.model_selection import train_test_split
          

          
X = df.drop(['price'],axis=1)
          
y = df['price']
          

          
X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
          

          
# 然后将训练集进一步划分为训练集和验证集
          
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.125, random_state=42)  # 0.125 x 0.8 = 0.1
          

          
import lightgbm as lgb
          

          
# LightGBM模型参数
          
params_lgb = {
          
    'learning_rate': 0.02,          # 学习率,控制每一步的步长,用于防止过拟合。典型值范围:0.01 - 0.1
          
    'boosting_type': 'gbdt',        # 提升方法,这里使用梯度提升树(Gradient Boosting Decision Tree,简称GBDT)
          
    'objective': 'mse',             # 损失函数
          
    'metric': 'rmse',               # 评估指标
          
    'num_leaves': 127,              # 每棵树的叶子节点数量,控制模型复杂度。较大值可以提高模型复杂度但可能导致过拟合
          
    'verbose': -1,                  # 控制 LightGBM 输出信息的详细程度,-1表示无输出,0表示最少输出,正数表示输出更多信息
          
    'seed': 42,                     # 随机种子,用于重现模型的结果
          
    'n_jobs': -1,                   # 并行运算的线程数量,-1表示使用所有可用的CPU核心
          
    'feature_fraction': 0.8,        # 每棵树随机选择的特征比例,用于增加模型的泛化能力
          
    'bagging_fraction': 0.9,        # 每次迭代时随机选择的样本比例,用于增加模型的泛化能力
          
    'bagging_freq': 4               # 每隔多少次迭代进行一次bagging操作,用于增加模型的泛化能力
          
}
          

          
model_lgb = lgb.LGBMRegressor(**params_lgb)
          
model_lgb.fit(X_train, y_train, eval_set=[(X_val, y_val)], 
          
              eval_metric='rmse')
      

picture.image

使用LightGBM模型对房价进行预测,并通过划分训练集、验证集和测试集的方式来训练模型、验证其性能,以确保模型的泛化能力,接下来也将对这个模型进行力图的绘制,数据集是一个包含了房价预测相关的特征信息数据,如中位收入、房龄、平均房间数、平均卧室数、人口数、平均家庭人口数、纬度和经度,以及对应的房价

基础力图绘制


          
import shap
          
# 构建 shap解释器
          
explainer = shap.TreeExplainer(model_lgb)
          
# 计算测试集的shap值
          
shap_values = explainer.shap_values(X_test)
          

          
# 绘制单个样本的SHAP解释(Force Plot)
          
sample_index = 7  # 选择一个样本索引进行解释
          
shap.force_plot(explainer.expected_value, shap_values[sample_index], X_test.iloc[sample_index], matplotlib=True)
          
plt.savefig("SHAP力图_1.pdf", format='pdf', bbox_inches='tight')
      

picture.image

这是一个基础的SHAP力图,目前在许多文章中采用了类似的展示形式,然而,这种样式仍有许多值得我们深入探讨的地方,例如,当特征数量过多时,如果我们只想展示部分关键特征,该如何实现?又如,特征带有度量单位时,如何在力图上清晰地展示?这些都是可以改进的方向,作者在一篇文献中发现了类似的SHAP力图如下:

picture.image

接下来我们通过一步步解读参数,根据原理去绘制类似的力图


        
            

          
 explainer
 .expected\_value
 
        
      

picture.image

explainer.expected_value 是SHAP解释器中的一个关键参数,它代表了模型在没有任何特征输入时的预测值,即模型输出的基准值或平均值,在回归问题中,这通常是模型在整个训练数据集上的平均预测值,这个值作为SHAP力图中的基础线,所有特征的SHAP值都相对于这个基准值进行调整,从而显示出每个特征对最终预测的贡献


        
            

          
 shap\_values
 [sample\_index]
 
        
      

picture.image

shap_values[sample_index] 表示SHAP解释器对第 sample_index 个样本计算出的各个特征的SHAP值


        
            

          
 X\_test
 .iloc
 [sample\_index]
 
        
      

picture.image

X_test.iloc[sample_index] 返回的是测试集 X_test 中第 sample_index 个样本的特征值也就是前文shap对应的样本,可以发现它本身是不带度量单位的,接下来根据这个原理去绘制带度量单位的shap力图

带度量单位的shap力图


          
base_value = explainer.expected_value  # 基础值,一般是模型在训练集上的平均输出
          
shap_values = shap_values[sample_index]  # 每个特征的SHAP值
          
features = np.array([
          
    'MedInc=-0.096140 ($1000)',          # 中位收入,单位为千美元
          
    'HouseAge=0.749907 (years)',         # 房龄,单位为年
          
    'AveRooms=-0.195315 (rooms/house)',  # 每个家庭的平均房间数
          
    'AveBedrms=-0.111900 (bedrooms/house)',  # 每个家庭的平均卧室数
          
    'Population=-0.367422 (people)',     # 人口数
          
    'AveOccup=0.053259 (people/house)',  # 每个家庭的平均人口数
          
    'Latitude=-0.807184 (degrees)',      # 纬度,单位为度
          
    'Longitude=0.749004 (degrees)'])# 经度,单位为度 特征名称和数值
          
# 创建力图
          
shap.force_plot(base_value, shap_values, features, 
          
                matplotlib=True,  # 使用Matplotlib来显示图像
          
                show=False) 
          

          
plt.savefig("SHAP力图_2.pdf", format='pdf', bbox_inches='tight')
      

picture.image

根据特定样本的特征值和SHAP值生成并保存一个解释模型预测的力图,可以发现该力图对于每个特征都存在一个其对应的单位,但是存在折叠,或许在实际应用中我们只希望展示部分特征就可以了,而不是每个特征都进行展示,只需要添加参数调整阈值就好了

特征展示控制


          
# 创建力图
          
shap.force_plot(base_value, shap_values, features, 
          
                matplotlib=True,  # 使用Matplotlib来显示图像
          
                show=False, 
          
                contribution_threshold=0.1)  # 调整阈值以控制显示哪些特征
          

          
plt.savefig("SHAP力图_3.pdf", format='pdf', bbox_inches='tight')
      

picture.image

通过添加 contribution_threshold=0.1 参数,我们可以调整SHAP力图中的显示阈值,对比两幅力图后可以发现,特征 HouseAge 已不在当前的力图中显示,因为它对预测结果的贡献较小。这种调整并未改变图表的整体信息表达,同时也使图表更加简洁,读者可以根据具体需求自行调整阈值,以更好地控制特征的展示效果

往期推荐

利用SHAP解释二分类模型的四种机器学习GUI工具

模型过拟合与欠拟合的核心原理及其与数据集分割的关系

复现顶刊Streamlit部署预测模型APP

数据预处理全攻略:从缺失值到特征工程,一站式解决方案

精确度与参数的完美融合:用可视化解读模型优化过程

特征选择:Lasso和Boruta算法的结合应用

提升机器学习精度:利用SHAP值与蒙特卡洛模拟优化特征选择

用图表说话:如何有效呈现回归预测模型结果

特征选择:基于随机森林的Boruta算法应用

picture.image

picture.image

picture.image

微信号|deep_ML

欢迎添加作者微信进入Python、ChatGPT群

进群请备注Python或AI进入相关群
无需科学上网、同步官网所有功能、使用无限制

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
高性能存储虚拟化方案 NVMe over Fabric 在火山引擎的演进
在云计算中,虚拟化存储扮演着重要角色,其中 iSCSI 协议在业界开放、流行多年。近年来,拥有更优性能的 NVMe over Fabrics 协议也得到了发展。本次分享介绍了 NVMe over Fabrics 在云原生和虚拟化方向的演进工作和成果。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论