3. SHAP 计算实战:使用 Python 的 shap 库计算单样本与全局 SHAP 值

本章是 SHAP 值监控的实操起点。我们将使用 Python 的 shap 库,分别计算单样本(局部解释)和全局(整体特征重要性)SHAP 值。理解这两种计算方式,是后续监控特征贡献漂移和阈值漂移的基础。

前置准备:确保已安装 shap 库(pip install shap),并准备一个训练好的模型(本实战使用 XGBoost 分类器)和对应的特征数据。

3.1 单样本 SHAP 值计算(局部解释)

单样本 SHAP 值回答的是:“对于这一个预测结果,每个特征贡献了多少?” 它基于 Shapley 值理论,为每个特征分配一个边际贡献值。

计算步骤:

  1. 创建解释器:使用 shap.TreeExplainer(model) 为树模型创建解释器。
  2. 计算单个样本:调用 explainer.shap_values(X_sample) 或 explainer(X_sample)。
  3. 可视化:使用 shap.force_plot() 或 shap.waterfall_plot() 展示单个样本的特征贡献。
import shap
import xgboost as xgb
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

# 1. 加载数据并训练模型
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = xgb.XGBClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# 2. 创建 TreeExplainer
explainer = shap.TreeExplainer(model)

# 3. 选取测试集第一个样本
X_sample = X_test[:1]

# 4. 计算单样本 SHAP 值
shap_values_single = explainer.shap_values(X_sample)

# 5. 输出结果
print("单样本 SHAP 值形状:", shap_values_single.shape)
print("特征名称:", load_breast_cancer().feature_names)
print("SHAP 值:", shap_values_single[0])

# 6. 可视化(可选,在 Jupyter 中运行)
# shap.force_plot(explainer.expected_value, shap_values_single[0], X_sample, feature_names=load_breast_cancer().feature_names)
关键理解:单样本 SHAP 值的总和加上模型的期望输出(base value)等于该样本的预测值。正 SHAP 值表示该特征将预测值推向正类(1),负值则推向反类(0)。
单样本 SHAP 值计算流程 输入单样本 TreeExplainer SHAP 值数组 Base Value 最终预测值 公式:预测值 = Base Value + Σ(每个特征的 SHAP 值) 正 SHAP 值 → 推动预测向正类;负 SHAP 值 → 推动预测向反类

3.2 全局 SHAP 值计算(特征重要性)

全局 SHAP 值回答的是:“在整个数据集上,哪些特征对模型预测最重要?” 常用两种聚合方式:平均绝对 SHAP 值和SHAP 依赖图。

计算步骤:

  1. 批量计算:对测试集或全量数据调用 explainer.shap_values(X)。
  2. 聚合重要性:计算每个特征的平均绝对 SHAP 值(np.abs(shap_values).mean(axis=0))。
  3. 可视化:使用 shap.summary_plot() 或 shap.bar_plot() 展示全局特征重要性。
import numpy as np

# 1. 计算整个测试集的 SHAP 值
shap_values_all = explainer.shap_values(X_test)

# 2. 计算全局特征重要性(平均绝对 SHAP 值)
feature_names = load_breast_cancer().feature_names
global_importance = np.abs(shap_values_all).mean(axis=0)

# 3. 排序并输出 Top-5 特征
sorted_idx = np.argsort(global_importance)[::-1]
print("全局特征重要性(Top-5):")
for i in range(5):
    idx = sorted_idx[i]
    print(f"  {i+1}. {feature_names[idx]}: {global_importance[idx]:.4f}")

# 4. 可视化(可选,在 Jupyter 中运行)
# shap.summary_plot(shap_values_all, X_test, feature_names=feature_names)
# shap.bar_plot(shap_values_all, X_test, feature_names=feature_names)
注意:全局 SHAP 值反映的是特征在整个数据集上的平均贡献,不代表每个样本的局部贡献。当监控到全局特征重要性发生漂移时,应进一步检查具体样本的局部 SHAP 值变化。
全局 SHAP 值计算与聚合流程 批量数据 X 批量 SHAP 值矩阵 平均绝对 SHAP 值 降序排序 Top-K 重要特征 全局重要性 = mean(|SHAP 值|) —— 衡量特征在整体上的平均影响强度 用于监控:当 Top-K 特征排名或数值发生显著变化时,提示模型行为漂移

3.3 单样本 vs 全局 SHAP 对比

对比维度 单样本 SHAP(局部) 全局 SHAP(整体)
计算对象 单个样本 整个数据集或测试集
输出形式 每个特征一个 SHAP 值(可正可负) 每个特征一个平均绝对 SHAP 值(非负)
用途 解释单个预测、调试异常样本 特征选择、监控特征重要性漂移
可视化工具 force_plot, waterfall_plot summary_plot, bar_plot
对监控的意义 检测单个样本的特征贡献异常 检测整体特征重要性的分布漂移
实战建议:在 MLOps 监控中,建议同时计算单样本和全局 SHAP 值。全局监控用于触发告警(如 Top-3 特征排名变化),单样本监控用于根因分析(如具体哪个样本的特征贡献异常)。