优化SHAP主效应图拟合曲线与交点标注直观展示特征影响变化与趋势

机器学习算法数据库

picture.image

背景

SHAP主效应值 ,即该特征在独立作用时对模型预测的贡献,这种方式剥离了交互效应的影响,更加直观地展现了主效应的变化趋势,为分析特征的独立作用提供了清晰的视角,有助于更深入地理解模型的特征行为,详情参考文章——期刊配图:SHAP主效应图绘制解释单个特征在独立作用时对模型预测的贡献

然而,仅仅展示主效应值的分布还不够直观。 拟合曲线 的引入,基于LOWESS(局部加权回归)的平滑曲线【当然其它拟合方法也可以,这里参考的是以下shap依赖图绘制的文章,也是往期文章——文献复现——优化SHAP依赖图拟合曲线与交点标注的新应用】,可以更好地捕捉主效应的全局趋势,揭示模型对特征的敏感性变化。同时, 交点标注 则进一步突出关键点——即SHAP值为0的位置,这些交点反映特征从正向影响到负向影响的临界点,为在特征影响变化与趋势提供参考

picture.image

代码实现

模型构建


          
import pandas as pd
          
import numpy as np
          
import matplotlib.pyplot as plt 
          
import warnings
          
warnings.filterwarnings("ignore")
          

          
plt.rcParams['font.family'] = 'Times New Roman'
          
plt.rcParams['axes.unicode_minus'] = False
          
df = pd.read_excel('2024-12-17-公众号Python机器学习AI.xlsx')
          
from sklearn.model_selection import train_test_split, KFold
          

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

          
# 划分训练集和测试集
          
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 optuna  
          
from xgboost import XGBRegressor  
          
from sklearn.metrics import mean_squared_error
          
def objective(trial):
          
    params = {
          
        'n_estimators': trial.suggest_categorical('n_estimators', [50, 100, 200, 300]), 
          
        'max_depth': trial.suggest_int('max_depth', 3, 15, step=1), 
          
        'learning_rate': trial.suggest_loguniform('learning_rate', 0.01, 0.3), 
          
        'subsample': trial.suggest_uniform('subsample', 0.5, 1.0), 
          
        'colsample_bytree': trial.suggest_uniform('colsample_bytree', 0.5, 1.0),
          
        'gamma': trial.suggest_uniform('gamma', 0, 5)
          
    }
          

          
    model = XGBRegressor(**params, random_state=42)
          
    model.fit(X_train, y_train)
          
    y_pred = model.predict(X_val)
          
    return mean_squared_error(y_val, y_pred)
          

          
study = optuna.create_study(direction="minimize")
          
study.optimize(objective, n_trials=100)
          
print("Best parameters:", study.best_params)
          
best_model = XGBRegressor(**study.best_params, random_state=42)
          
best_model.fit(X_train, y_train)
      

picture.image

使用Optuna优化XGBoost模型的超参数,并使用最佳参数训练最终模型,为后续基于SHAP值的特征重要性和主效应分析提供模型基础

基础shap主效应图绘制


        
            

          main\_effects\_df
        
      

picture.image

计算测试集的主效应值,并将结果存储为main_effects_df,展示每个特征在测试集上的主效应值,代码与数据集获取:如需获取本文的源代码和数据集,请添加作者微信联系


          
num_rows, num_cols = 2, 4  # 设置2行4列
          
features = main_effects_df.columns[:num_rows * num_cols]  # 取出需要绘制的特征
          
fig, axes = plt.subplots(nrows=num_rows, ncols=num_cols, figsize=(15, 8), dpi=1200)
          
for i, feature in enumerate(features):
          
    row, col = divmod(i, num_cols)  
          
    ax = axes[row, col]
          
    ax.scatter(X_test[feature], main_effects_df[feature], s=10)  
          
    ax.axhline(y=0, color='black', linestyle='-.', linewidth=1)
          
    ax.set_xlabel(feature, fontsize=10)
          
    ax.set_ylabel('SHAP main effect value', fontsize=10)
          
    ax.spines['top'].set_visible(False)
          
    ax.spines['right'].set_visible(False)
          

          
# 移除多余的子图
          
for i in range(len(features), num_rows * num_cols):
          
    row, col = divmod(i, num_cols)
          
    fig.delaxes(axes[row, col])
          

          
plt.tight_layout()
          
plt.savefig("1.png", bbox_inches='tight', dpi=1200)
          
plt.show()
      

picture.image

绘制测试集所有特征的主效应值散点图

shap主效应图+拟合曲线绘制


          
import seaborn as sns
          
from scipy.optimize import fsolve
          
# 绘制散点图
          
plt.figure(figsize=(8, 6), dpi=300)
          
plt.scatter(X_test['X_1'], main_effects_df['X_1'], s=20, label='SHAP values', alpha=0.7)
          

          
# 添加LOWESS拟合曲线
          
sns.regplot(x=X_test['X_1'], y=main_effects_df['X_1'], scatter=False, lowess=True, color='lightcoral', label='LOWESS Curve')
          

          
# 添加shap=0的横线
          
plt.axhline(y=0, color='black', linestyle='-.', linewidth=1, label='SHAP = 0')
          

          
# 添加图例
          
plt.legend()
          

          
# 设置标签和标题
          
plt.xlabel('X_1', fontsize=12)
          
plt.ylabel('SHAP main effect value', fontsize=12)
          
# 去除上和右的边框线
          
ax = plt.gca()
          
ax.spines['top'].set_visible(False)
          
ax.spines['right'].set_visible(False)
          
# 保存并显示图像
          
plt.savefig("2.png", bbox_inches='tight', dpi=1200)
          
plt.show()
      

picture.image

通过引入LOWESS拟合曲线,在SHAP主效应散点图中添加一条平滑的趋势线,使特征值与主效应值的关系更加直观。同时,通过绘制SHAP值为0的基准线,明确了正负效应的分界点,为分析特征影响的变化趋势提供了更清晰的可视化支持

shap主效应图+拟合曲线+交点标注绘制


          
# 绘制散点图
          
plt.figure(figsize=(8, 6), dpi=300)
          
plt.scatter(X_test['X_1'], main_effects_df['X_1'], s=20, label='SHAP values', alpha=0.7)
          

          
# 添加LOWESS拟合曲线
          
sns.regplot(x=X_test['X_1'], y=main_effects_df['X_1'], scatter=False, lowess=True, color='lightcoral', label='LOWESS Curve')
          

          
# 使用 LOWESS 数据生成拟合曲线
          
lowess_data = sns.regplot(x=X_test['X_1'], y=main_effects_df['X_1'], scatter=False, lowess=True, color='lightcoral')
          
line = lowess_data.get_lines()[0]  # 拟合线条对象
          
x_fit = line.get_xdata()  # LOWESS 拟合线的 x 轴数据
          
y_fit = line.get_ydata()  # LOWESS 拟合线的 y 轴数据
          

          
# 找出所有与 y=0 相交的 x 值
          
def find_zero_crossings(x_fit, y_fit):
          
    crossings = []
          
    for i in range(1, len(y_fit)):
          
        if (y_fit[i-1] < 0 and y_fit[i] > 0) or (y_fit[i-1] > 0 and y_fit[i] < 0):
          
            # 使用插值法找到 x_fit 和 y_fit 中 y 值接近 0 的 x 值
          
            crossing = fsolve(lambda x: np.interp(x, x_fit, y_fit), x_fit[i])[0]
          
            crossings.append(crossing)
          
    return crossings
          

          
x_intercepts = find_zero_crossings(x_fit, y_fit)
          

          
# 在图中标注所有的 x_intercepts
          
for x_intercept in x_intercepts:
          
    plt.axvline(x=x_intercept, color='blue', linestyle='--', label=f'Intersection at X_1 = {x_intercept:.2f}')
          
    plt.text(x_intercept, 0.2, f'X_1 = {x_intercept:.2f}', color='black', fontsize=10, verticalalignment='bottom')
          

          
# 添加shap=0的横线
          
plt.axhline(y=0, color='black', linestyle='-.', linewidth=1, label='SHAP = 0')
          

          
# 添加图例
          
plt.legend()
          

          
# 设置标签和标题
          
plt.xlabel('X_1', fontsize=12)
          
plt.ylabel('SHAP main effect value', fontsize=12)
          
# 去除上和右的边框线
          
ax = plt.gca()
          
ax.spines['top'].set_visible(False)
          
ax.spines['right'].set_visible(False)
          
# 保存并显示图像
          
plt.savefig("3.png", bbox_inches='tight', dpi=1200)
          
plt.show()
      

picture.image

在绘制SHAP主效应散点图和LOWESS拟合曲线的基础上,进一步通过拟合曲线数据提取交点,明确特征值对模型输出影响的关键转折点,并在图中用虚线和文本标注交点位置。相比之前的代码,这里不仅展示了特征对模型输出的整体趋势,还揭示SHAP值从正向影响转为负向影响的临界值范围,为特征解释提供参考

绘制所有特征可视化


          
num_rows, num_cols = 2, 4  # 设置2行4列
          
features = main_effects_df.columns[:num_rows * num_cols]  # 取出需要绘制的特征
          
fig, axes = plt.subplots(nrows=num_rows, ncols=num_cols, figsize=(15, 8), dpi=1200)
          

          
def find_zero_crossings(x_fit, y_fit):
          
    crossings = []
          
    for i in range(1, len(y_fit)):
          
        if (y_fit[i-1] < 0 and y_fit[i] > 0) or (y_fit[i-1] > 0 and y_fit[i] < 0):
          
            crossing = fsolve(lambda x: np.interp(x, x_fit, y_fit), x_fit[i])[0]
          
            crossings.append(crossing)
          
    return crossings
          

          
for i, feature in enumerate(features):
          
    row, col = divmod(i, num_cols)  
          
    ax = axes[row, col]
          
    ax.scatter(X_test[feature], main_effects_df[feature], s=10)  
          

          
    # 添加LOWESS拟合曲线
          
    sns.regplot(x=X_test[feature], y=main_effects_df[feature], scatter=False, lowess=True, ax=ax, color='lightcoral')
          

          
    # 获取LOWESS拟合曲线数据
          
    lowess_data = sns.regplot(x=X_test[feature], y=main_effects_df[feature], scatter=False, lowess=True, ax=ax, color='lightcoral')
          
    line = lowess_data.get_lines()[0]  
          
    x_fit = line.get_xdata()  
          
    y_fit = line.get_ydata()  
          

          
    # 找出与y=0相交的x值
          
    x_intercepts = find_zero_crossings(x_fit, y_fit)
          

          
    # 标注交点
          
    for x_intercept in x_intercepts:
          
        ax.axvline(x=x_intercept, color='blue', linestyle='--', label=f'X = {x_intercept:.2f}')
          
        ax.text(x_intercept, 0.02, f'{x_intercept:.2f}', color='black', fontsize=8, verticalalignment='bottom')
          

          
    # 添加shap=0的横线
          
    ax.axhline(y=0, color='black', linestyle='-.', linewidth=1)
          

          
    # 设置标签和标题
          
    ax.set_xlabel(feature, fontsize=10)
          
    ax.set_ylabel('SHAP main effect value', fontsize=10)
          
    ax.spines['top'].set_visible(False)
          
    ax.spines['right'].set_visible(False)
          

          
# 移除多余的子图
          
for i in range(len(features), num_rows * num_cols):
          
    row, col = divmod(i, num_cols)
          
    fig.delaxes(axes[row, col])
          

          
plt.tight_layout()
          
plt.savefig("4.png", bbox_inches='tight', dpi=1200)
          
plt.show()
      

picture.image

绘制多个特征的SHAP主效应值散点图,结合LOWESS拟合曲线展示特征值与主效应值的趋势,并标注拟合曲线与SHAP值为0的交点,直观呈现特征影响的关键变化点,代码与数据集获取:如需获取本文的源代码和数据集,请添加作者微信联系

往期推荐

从模型构建到在线部署:基于Stacking集成模型的全流程实现与SHAP可视化

探究SHAP交互效应:基于shap.dependence_plot与自定义可视化方法的对比分析

利用Optuna TPE算法优化RF模型及3D曲面图展示调参过程

nature medicine二分类结局随机森林模型构建与评估复现

期刊配图:分类变量SHAP值的箱线图及可视化优化展示

如何用SHAP解读集成学习Stacking中的基学习器和元学习器以及整体模型贡献

从入门到实践:如何利用Stacking集成多种机器学习算法提高模型性能

整合数据分布+拟合线+置信区间+相关系数的皮尔逊相关可视化

期刊配图:通过变量热图展示样本与模型预测的关联信息

期刊配图:如何有效呈现回归、分类模型的评价指标

picture.image

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

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
相关资源
火山引擎 EMR 基于 Proton 的存算分离实践
EMR 团队针对这些挑战自研了 Proton 加速引擎,深度优化对象存储读写能力,与 Hive/Spark/Trino 等计算引擎集成后,在不改变用户使用习惯的前提条件下,可提供对象存储数据集的透明加速服务。在离线场景下,其性能基本持平存算一体架构。本次分享将介绍 Proton 技术能力和最佳实践。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论