mcpField
S
shap-model-explainability

shap-model-explainability

github.com/jaechang-hits数据与数据库38473 次安装6 天前更新
代码仓库

关于 shap-model-explainability

shap-model-explainability 是一项使用 SHAP 解释机器学习预测的技能,涵盖解释器选择,以及对不同模型进行局部、全局和特征关系分析。

主要功能

  1. 01按模型类型选择解释器
  2. 02计算特征归因值
  3. 03解释单条预测
  4. 04汇总全局特征重要性
  5. 05可视化特征关系
  6. 06比较不同群组的解释结果

适用场景

  1. 01查明影响某项预测的特征
  2. 02排查模型行为和潜在数据泄漏
  3. 03比较不同人口群体的模型解释
  4. 04向利益相关方展示模型解释

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill shap-model-explainability

安装后在 Claude Code 中输入/shap-model-explainability确认已加载。

附带文件references/theory.md

详细介绍

SHAP 模型可解释性

概述

SHAP(SHapley Additive exPlanations)是一个统一框架,使用合作博弈论中的 Shapley 值解释机器学习模型的预测结果。它量化每个特征对单个预测的贡献,并提供局部(单个样本级)和全局(数据集级)解释,同时在一致性和可加性方面提供理论保证。

适用场景

  • 解释哪些特征驱动模型的预测结果(全局重要性)
  • 了解模型为何做出特定预测(局部解释)
  • 调试模型行为并识别数据泄漏
  • 分析模型在不同人口群体中的公平性
  • 比较多个模型之间的特征重要性
  • 为利益相关者生成可解释的模型说明
  • 对于基于树的模型解释,优先使用 SHAP,而非置换重要性或基尼重要性(更准确,可达到实例级)
  • 对图像进行深度学习解释时,可考虑 GradCAM;对于表格/结构化数据,请使用 SHAP

前提条件

pip install shap matplotlib
# Optional: xgboost lightgbm tensorflow torch (depending on model)

快速开始

import shap
import xgboost as xgb
from sklearn.model_selection import train_test_split

# Load example data
X, y = shap.datasets.adult()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# Train model
model = xgb.XGBClassifier(n_estimators=100).fit(X_train, y_train)

# Explain: select explainer → compute → visualize
explainer = shap.TreeExplainer(model)
shap_values = explainer(X_test)

shap.plots.beeswarm(shap_values)   # Global importance
shap.plots.waterfall(shap_values[0])  # Single prediction
print(f"Base value: {shap_values.base_values[0]:.3f}")
print(f"SHAP values shape: {shap_values.values.shape}")  # (n_samples, n_features)

工作流

步骤 1:选择合适的解释器

根据模型类型选择:

模型类型解释器速度精确性
基于树的模型(XGBoost、LightGBM、RF、CatBoost)TreeExplainer快精确
线性模型(LogReg、GLM、Ridge)LinearExplainer即时精确
深度学习(TensorFlow、PyTorch)DeepExplainer快近似
深度学习(基于梯度)GradientExplainer快近似
任意模型(黑盒)KernelExplainer慢近似
任意模型(基于置换)PermutationExplainer非常慢精确
不确定?shap.Explainer自动自动
# Tree-based models (most common)
explainer = shap.TreeExplainer(model)

# Linear models
explainer = shap.LinearExplainer(model, X_train)

# Deep learning
explainer = shap.DeepExplainer(model, X_train[:100])

# Any model (model-agnostic, slower)
explainer = shap.KernelExplainer(model.predict, shap.kmeans(X_train, 50))

# Auto-select
explainer = shap.Explainer(model, X_train)
步骤 2:计算 SHAP 值
shap_values = explainer(X_test)

# shap_values object contains:
# .values      — SHAP values array (n_samples, n_features)
# .base_values — Expected model output (baseline)
# .data        — Original feature values

# Verify additivity: prediction = base_value + sum(SHAP values)
print(f"  {shap_values.base_values[0]:.3f} + {shap_values.values[0].sum():.3f} = "
      f"{shap_values.base_values[0] + shap_values.values[0].sum():.3f}")
步骤 3:全局解释
# Beeswarm: feature importance + value distributions (most informative)
shap.plots.beeswarm(shap_values, max_display=15)

# Bar: clean mean |SHAP| importance
shap.plots.bar(shap_values)
步骤 4:局部解释(单个预测)
# Waterfall: detailed breakdown of one prediction
shap.plots.waterfall(shap_values[0])

# Force: additive force visualization
shap.plots.force(shap_values[0])
步骤 5:特征关系
# Scatter: how a feature affects predictions
shap.plots.scatter(shap_values[:, "Age"])

# Colored by interaction feature
shap.plots.scatter(shap_values[:, "Age"], color=shap_values[:, "Education-Num"])
步骤 6:高级可视化
# Heatmap: multi-sample SHAP grid
shap.plots.heatmap(shap_values[:100])

# Decision plot: cumulative SHAP paths
shap.plots.decision(shap_values.base_values[0], shap_values.values[:10],
                     feature_names=X_test.columns.tolist())

# Cohort comparison
import numpy as np
mask_a = X_test["Age"] < 40
shap.plots.bar({
    "Under 40": shap_values[mask_a],
    "40+": shap_values[~mask_a]
})

关键参数

参数解释器/函数默认值效果
feature_perturbationTreeExplainer"tree_path_dependent"使用 "interventional" 进行因果解释(需要背景数据)
model_outputTreeExplainer"raw"使用 "probability" 解释概率,而非对数几率
data(背景数据)KernelExplainer、DeepExplainer必需100-1000 个有代表性的样本;使用 shap.kmeans(X, 50) 提高效率
nsamplesKernelExplainer"auto"值越高越准确,但速度越慢;最少为特征数的 2 倍
max_display所有绘图函数10图中显示的特征数量
alphascatter/beeswarm1.0密集数据集中的点透明度
show所有绘图函数True设置为 False 可获取 matplotlib 图形以便保存
clusteringbeeswarmNone使用 shap.utils.hclust(...) 对相关特征进行聚类

核心概念

SHAP 值的性质

SHAP 值具有三项理论保证(这是解释方法中独有的):

  • 可加性:prediction = base_value + sum(SHAP values) — 精确分解
  • 一致性:如果某个特征在模型中的重要性增加,其 SHAP 值也会增加
  • 缺失性:不存在的特征会获得零归因

解释:正 SHAP 值 → 推高预测结果;负值 → 降低预测结果;绝对值大小 → 影响强度。

模型输出类型

了解模型输出的内容 — SHAP 解释的是输出空间:

  • 回归:SHAP 值以目标单位表示(例如,美元、温度)
  • 分类(对数几率):树分类器的默认设置。使用 model_output="probability" 可解释概率
  • 分类(概率):SHAP 值之和等于相对于基线的概率偏差
SHAP 与其他方法的对比
方法局部全局一致与模型无关
SHAP是是是是
排列重要性否是否是
Gini/分裂重要性否是否仅适用于树模型
LIME是否否是
积分梯度是否部分仅适用于 NN
交互值(仅适用于 TreeExplainer)
shap_interaction = explainer.shap_interaction_values(X_test)
# Shape: (n_samples, n_features, n_features)
# Diagonal = main effects; off-diagonal = pairwise interactions
背景数据选择

背景数据用于确定基线(模型输出的期望值)。数据选择会影响 SHAP 值的大小,但不会影响相对重要性。

  • 从训练数据中随机抽样:100-500 个样本
  • 使用 shap.kmeans(X_train, 50) 进行高效汇总
  • 对于 tree_path_dependent 模式下的 TreeExplainer:无需背景数据(使用树结构)
  • 对于 DeepExplainer/KernelExplainer:使用 100-1000 个样本,在准确度与速度之间取得平衡

常用方案

方案:模型调试
import numpy as np

# Find misclassified samples
predictions = model.predict(X_test)
errors = predictions != y_test
error_indices = np.where(errors)[0]

# Explain errors
for idx in error_indices[:3]:
    print(f"Sample {idx}: predicted={predictions[idx]}, actual={y_test.iloc[idx]}")
    shap.plots.waterfall(shap_values[idx])

# Check for data leakage: unexpected high-importance features
mean_abs_shap = np.abs(shap_values.values).mean(0)
top_features = X_test.columns[mean_abs_shap.argsort()[-5:]]
print(f"Top features (check for leakage): {list(top_features)}")
方案:公平性分析
# Compare SHAP distributions across groups
group_a = shap_values[X_test["Sex"] == 0]
group_b = shap_values[X_test["Sex"] == 1]

shap.plots.bar({"Female": group_a, "Male": group_b})

# Check protected attribute importance
sex_importance = np.abs(shap_values[:, "Sex"].values).mean()
total_importance = np.abs(shap_values.values).mean()
print(f"Sex contribution: {sex_importance/total_importance:.1%} of total importance")
方案:生产环境缓存
import joblib

# Save explainer for reuse
joblib.dump(explainer, 'explainer.pkl')
explainer = joblib.load('explainer.pkl')

# Batch computation for API responses
def explain_batch(X_batch, explainer, top_n=5):
    sv = explainer(X_batch)
    results = []
    for i in range(len(X_batch)):
        top_idx = np.abs(sv.values[i]).argsort()[-top_n:]
        results.append({
            'prediction': sv.base_values[i] + sv.values[i].sum(),
            'top_features': {X_batch.columns[j]: sv.values[i][j] for j in top_idx}
        })
    return results
方案:MLflow 集成
import mlflow
import matplotlib.pyplot as plt

with mlflow.start_run():
    model = xgb.XGBClassifier().fit(X_train, y_train)
    explainer = shap.TreeExplainer(model)
    shap_values = explainer(X_test)

    shap.plots.beeswarm(shap_values, show=False)
    mlflow.log_figure(plt.gcf(), "shap_beeswarm.png")
    plt.close()

    for feat, imp in zip(X_test.columns, np.abs(shap_values.values).mean(0)):
        mlflow.log_metric(f"shap_{feat}", imp)

预期输出

输出类型描述
shap_valuesshap.Explanation对象包含 .values (n_samples, n_features)、.base_values(基线)、.data(输入特征)
瀑布图matplotlib 图形单个实例的解释,展示从基准值到预测值的特征贡献
蜂群图matplotlib 图形全局摘要:所有样本的特征重要性 × 方向
条形图matplotlib 图形各特征的 SHAP 值绝对值均值(全局重要性排名)
力图HTML/matplotlib单次预测的交互式或静态可视化
mean_abs_shappd.Series各特征的 SHAP 值绝对值均值,用于排名和报告

故障排除

问题原因解决方案
计算非常缓慢对树模型使用了 KernelExplainer对基于树的模型使用 TreeExplainer
大型数据集上运行缓慢一次性计算所有样本对子集采样:explainer(X_test[:1000]),或分批计算
SHAP 值之和不等于预测值模型输出类型错误检查 model_output 参数;验证可加性
对数几率与概率混淆树分类器默认使用对数几率使用 TreeExplainer(model, model_output="probability")
图表过于杂乱显示的特征过多设置 max_display=10 或使用特征聚类
DeepExplainer 报错背景数据过少使用 100-1000 个背景样本
内存错误数据集较大且特征较多使用 shap.kmeans(X, 50) 减少背景数据
力图无法渲染笔记本中缺少 JS在笔记本开头运行 shap.initjs()
不同运行之间的重要性不一致KernelExplainer 的采样方差增大 nsamples 或使用确定性解释器
相关特征的重要性为负特征交互或相关性使用 feature_perturbation="interventional" 或散点图

随附资源

  • references/theory.md — 数学基础:Shapley 值公式、关键性质(可加性、对称性、虚设特征、单调性)、计算算法(Tree SHAP、Kernel SHAP、Deep SHAP、Linear SHAP)、条件期望(干预式与观测式)、与 LIME/DeepLIFT/LRP/Integrated Gradients 的比较、交互值、理论局限

未从原始内容迁移:references/explainers.md(340 行)——每个解释器类的详细构造函数参数、方法和性能基准。解释器选择指南和常见用法已在工作流步骤 1 和关键参数中介绍。

未从原始内容迁移:references/plots.md(508 行)——所有 9 种图表类型的完整参数参考,包含高级自定义(小提琴图、决策图、特征聚类)。主要图表类型已在工作流步骤 3–6 中介绍。

未从原始内容迁移:references/workflows.md(606 行)——特征工程、模型比较、深度学习解释、生产部署和时间序列的详细分步工作流。核心模式已在常见配方中介绍;扩展工作流请查阅原始内容。

最佳实践

  1. 优先选择专用解释器 — TreeExplainer > LinearExplainer > DeepExplainer > KernelExplainer。仅在没有专用解释器时使用与模型无关的解释器
  2. 先看全局,再看局部 — 从蜂群图/条形图开始,了解整体重要性,然后使用瀑布图/散点图查看单个预测和特征关系
  3. 使用多种可视化 — 不同图表会揭示不同见解;结合全局视图(蜂群图)+ 局部视图(瀑布图)+ 关系视图(散点图)
  4. 选择合适的背景数据 — 从训练数据中选取 100-500 个具有代表性的样本;使用 shap.kmeans() 提高效率
  5. 结合领域知识验证 — 特征重要性异常偏高可能表明存在数据泄漏,而非真正的预测能力
  6. 牢记 SHAP 展示的是关联,而非因果关系 — 特征的 SHAP 重要性较高,意味着模型使用了该特征,并不代表该特征会对结果产生因果影响
  7. 考虑特征相关性 — 相关特征会共享 SHAP 重要性;使用 feature_perturbation="interventional" 进行因果解释,或使用特征聚类查看分组重要性

参考资料

  • Lundberg & Lee(2017)。“A Unified Approach to Interpreting Model Predictions”(NeurIPS)
  • Lundberg 等(2020)。“From local explanations to global understanding with explainable AI for trees”(Nature Machine Intelligence)
  • 官方文档:https://shap.readthedocs.io/
  • GitHub:https://github.com/shap/shap

相关技能

  • scikit-learn-machine-learning — SHAP 分析的模型训练
  • matplotlib-scientific-plotting — 自定义 SHAP 图表样式和导出
  • statistical-analysis — 用于补充 SHAP 解释的统计检验

评论

支持 Markdown