背景
SHAP交互效应旨在剔除特征的主效应,专注于分析模型中特征之间的交互对SHAP值的影响。具体而言,交互效应值反映了一个特征对预测的贡献如何随着另一个特征的变化而变化。这种分析能够揭示特征之间的协同作用或竞争关系,为复杂模型的行为提供更深层次的解释。 通过分析交互效应,可以清晰地理解特征之间的相互依赖关系以及它们对模型预测的联合影响,具体参考往期文章——从代码实践理解SHAP值:主效应值与交互效应值的构成解析、期刊配图:SHAP主效应图绘制解释单个特征在独立作用时对模型预测的贡献、从代码实践理解SHAP值:主效应值与交互效应值的构成解析, 接下来聚焦于SHAP交互效应,通过对比shap.dependence_plot与自定义交互效应图的可视化效果的差异理解SHAP交互效应值
代码实现
模型构建
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-13-公众号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)
通过Optuna优化XGBoost回归模型的超参数,构建了一个性能优异的模型,为后续计算SHAP值并解释模型行为 做好准备
使用 shap_interaction_values 绘制
import shap
# 创建解释器
explainer = shap.TreeExplainer(best_model)
# 计算 SHAP 交互值
shap_interaction_values = explainer.shap_interaction_values(X_test)
shap.dependence_plot(("X_1", "X_2"), shap_interaction_values, X_test, show=False)
plt.savefig("shap_dependence_plot.pdf", format="pdf", dpi=1200)
plt.show()
使用SHAP自带的shap.dependence_plot函数,计算并可视化模型中两个特征(X_1和X_2)的交互效应值,直观展示它们对模型预测的联合影响
自定义可视化:基于SHAP交互效应值绘制特征间关系图
df\_1
df_1是提取的特征X_1对其他特征(如X_2等)的交互效应值,并将其存储在对应的列中,代码与数据集获取:如需获取本文的源代码和数据集,请添加作者微信联系
plt.figure(figsize=(6, 4), dpi=1200)
sc = plt.scatter(X_test["X_1"], df_1['df_X_1_X_2'],
s=10, c=X_test["X_2"], cmap='coolwarm')
cbar = plt.colorbar(sc, aspect=30, shrink=1) # 调整颜色条比例和长度
cbar.set_label('X_2', fontsize=12) # 设置颜色条标签
cbar.outline.set_visible(False)
plt.axhline(y=0, color='black', linestyle='-.', linewidth=1)
plt.xlabel('X_1', fontsize=12)
plt.ylabel('SHAP interaction value for\n X_1 and X_2', fontsize=12)
ax = plt.gca()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.savefig("SHAP interaction value for X_1 and X_2_1.pdf", format='pdf', bbox_inches='tight', dpi=1200)
plt.show()
使用自定义可视化,通过散点图展示特征X_1与X_2的交互效应值(基于SHAP),并使用颜色梯度表示X_2的取值,以直观地分析两特征对模型预测的联合影响,细心的读者可以发现,通过 shap_interaction_values绘制的交互效应图和自定义绘制的交互效应图,散点分布、x轴范围和颜色映射条范围完全一致,但两者在y轴的取值范围和标度上却存在明显差异,这是什么导致的呢
在SHAP交互值矩阵中:
- 对角线元素:表示每个特征的主效应值,即该特征对模型预测的独立贡献
- 非对角线元素:表示两个特征之间的交互效应值,即它们对模型预测的协同作用
- 对称性:非对角线元素的位置对称,例如X_1和X_2的交互效应值等于X_2和X_1的交互效应值,这种对称性表明SHAP交互值是双向的,强调了两个特征的联合影响是等价的
图中红色方框清楚地标出了这种对称性,可以观察到对应位置的值完全一致,所以当使用shap.dependence_plot绘制交互效应图时,它会将这两个值(X_1对X_2 的交互效应值和X_2对X_1的交互效应值)合并在一起进行展示,从而体现整体的交互效应强度,而自定义绘图仅选取单一方向的交互效应值(例如X_1对X_2),所以两者的y轴取值范围和标度存在差异【shap.dependence_plot交互图y轴是自定义绘图y轴的2倍】,这是因为自定义绘图没有考虑对称交互值的双向合并
plt.figure(figsize=(6, 4), dpi=1200)
sc = plt.scatter(X_test["X_1"], df_1['df_X_1_X_2']*2,
s=10, c=X_test["X_2"], cmap='coolwarm')
cbar = plt.colorbar(sc, aspect=30, shrink=1) # 调整颜色条比例和长度
cbar.set_label('X_2', fontsize=12) # 设置颜色条标签
cbar.outline.set_visible(False)
plt.axhline(y=0, color='black', linestyle='-.', linewidth=1)
plt.xlabel('X_1', fontsize=12)
plt.ylabel('SHAP interaction value for\n X_1 and X_2', fontsize=12)
ax = plt.gca()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.savefig("SHAP interaction value for X_1 and X_2_2.pdf", format='pdf', bbox_inches='tight', dpi=1200)
plt.show()
在自定义绘图中,只需要将df_1['df_X_1_X_2']乘以2(即df_1['df_X_1_X_2']*2),即可与 shap.dependence_plot绘制的交互效应图完全一致,这是因为shap.dependence_plot会将交互效应值的两个对称部分(如 X_1 对 X_2 和 X_2 对 X_1)合并
在考虑交互效应时,是否需要合并类似于讨论皮尔逊相关系数矩阵中是否将对称的相关系数进行相加,例如,X_1 和X_2的相关系数为0.7,X_2和X_1的相关系数同样为0.7,但我们在描述X_1和 X_2的相关性时,通常只会说相关系数为0.7,而不会将两者相加得出1.4
同样地,在分析SHAP的交互效应值时,是否需要合并对称的交互效应值(如X_1对X_2和X_2对 X_1),取决于分析的目的和读者的取舍
- 如果目标是展示整体交互强度,可以像 shap.dependence_plot 那样将两者合并,以体现特征间的综合交互作用
- 如果需要分析特定方向的交互效应(如X_1对X_2的单向影响),单个展示可能更加清晰直观
因此,这一选择本质上取决于分析场景和解释需求,合并或单独展示各有优劣,关键在于能否清晰地传达模型中特征交互效应的真实意义,这里的分析与建议仅代表作者个人理解,具体应用时还需结合实际问题与需求酌情判断,代码与数据集获取:如需获取本文的源代码和数据集,请添加作者微信联系
往期推荐
SHAP模型解释保姆级教程:回归、分类、基础到期刊配图全覆盖
复现SCI文章 SHAP 依赖图可视化以增强机器学习模型的可解释性
复现 Nature 图表——基于PCA的高维数据降维与可视化实践及其扩展
复现Nature图表——基于PCA降维与模型预测概率的分类效果可视化
如何用SHAP解读集成学习Stacking中的基学习器和元学习器以及整体模型贡献
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~
个人观点,仅供参考