SHAP 值计算公式与代码示例

1. 经典 SHAP 计算(Shapley 值)

SHAP 值基于 Shapley 值的定义,用于衡量每个特征对模型预测的贡献。

公式:
ϕi=∑S⊆{1,...,n}∖{i}∣S∣!(n−∣S∣−1)!n![f(S∪{i})−f(S)] \phi_i = \sum_{S \subseteq \{1, ..., n\} \setminus \{i\}} \frac{|S|! (n - |S| - 1)!}{n!} \Big[ f(S \cup \{i\}) - f(S) \Big] ϕi=S{1,...,n}{i}n!S!(nS1)![f(S{i})f(S)]

其中:

  • ϕi\phi_iϕi:特征 iii 的 SHAP 值。
  • SSS:包含除 iii 之外的特征子集。
  • f(S)f(S)f(S):仅使用子集 SSS 进行预测的模型输出。
  • f(S∪{i})f(S \cup \{i\})f(S{i}):加入 iii 之后的预测值。
  • 组合系数 ∣S∣!(n−∣S∣−1)!n!\frac{|S|! (n - |S| - 1)!}{n!}n!S!(nS1)! 确保所有子集的贡献被公平分配。

代码示例

import itertools
import numpy as np

def shap_value(model, X, i):
    """ 计算特征 i 的 SHAP 值 """
    n = X.shape[1]  # 特征总数
    phi_i = 0  # 初始化 SHAP 值

    for S in itertools.combinations([j for j in range(n) if j != i], r=None):
        S = list(S)
        weight = np.math.factorial(len(S)) * np.math.factorial(n - len(S) - 1) / np.math.factorial(n)
        f_S = model.predict(X[:, S].mean(axis=0, keepdims=True))  # 仅用 S 预测
        f_Si = model.predict(X[:, S + [i]].mean(axis=0, keepdims=True))  # S + i 预测
        phi_i += weight * (f_Si - f_S)

    return phi_i

shap_values = [shap_value(model, X, i) for i in range(X.shape[1])]

注意:此方法计算复杂度为 O(2^n),高维数据不适用。

  1. Deep SHAP(深度学习 SHAP)

Deep SHAP 结合 DeepLIFT,通过基线输入(baseline)计算输入特征相对于基线的贡献。

公式:
ϕi=(xi−x’i)⋅∂f(x)∂xi∣x’ \phi_i = (x_i - x’i) \cdot \frac{\partial f(x)}{\partial x_i} \Big|{x’} ϕi=(xixi)xif(x) x

期望 SHAP 计算:
ϕi=Ex’∼P(x’)[(xi−x’i)⋅∂f(x)∂xi∣x’] \phi_i = \mathbb{E}_{x’ \sim P(x’)} \Big[ (x_i - x’i) \cdot \frac{\partial f(x)}{\partial x_i} \Big|{x’} \Big] ϕi=ExP(x)[(xixi)xif(x) x]

其中:
x’x’x 是基线输入(如零输入、均值输入)。
P(x’)P(x’)P(x) 是基线输入的分布,用多个样本求期望。
• 计算输入 xix_ixi 相对于基线 x’ix’_ixi 的贡献,结合梯度信息衡量 SHAP 值。

代码示例

import shap
import torch

X_baseline = X_train.mean(axis=0, keepdims=True)  # 均值作为基线输入
explainer = shap.DeepExplainer(model, torch.tensor(X_baseline, dtype=torch.float32))
shap_values = explainer.shap_values(torch.tensor(X_test, dtype=torch.float32))

适用场景:深度学习(如 CNN、RNN、Transformer)。

  1. Kernel SHAP(通用模型)

Kernel SHAP 采用加权线性回归近似 SHAP 值。

公式:
ϕ=arg⁡min⁡ϕ∑S⊆Nw(S)(f(S)−∑i∈Sϕi)2 \phi = \arg\min_{\phi} \sum_{S \subseteq N} w(S) \Big( f(S) - \sum_{i \in S} \phi_i \Big)^2 ϕ=argϕminSNw(S)(f(S)iSϕi)2

其中:
w(S)w(S)w(S) 是加权因子,近似 Shapley 值。

代码示例

import shap
explainer = shap.KernelExplainer(model.predict, X_train)
shap_values = explainer.shap_values(X_test)

适用场景:适用于任何黑盒模型,但计算较慢。

  1. Tree SHAP(决策树)

Tree SHAP 针对 决策树(XGBoost, LightGBM) 进行了优化,计算复杂度降低:

复杂度:
O(TL) O(TL) O(TL)
其中:
TTT 是树的数量。
LLL 是树的最大深度。

代码示例

explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)

适用场景:梯度提升树(GBDT、XGBoost、LightGBM)。

  1. 处理 Embedding 特征的 SHAP 计算

当特征经过 Embedding 层 变成 多维向量,每个 SHAP 计算都会返回多个 SHAP 值,例如:

X_category → Embedding → (d_embedding × SHAP values)

如何衡量整个特征的影响?

  1. 绝对值均值: 1d∑i=1dϕi\frac{1}{d} \sum_{i=1}^{d} \phi_id1i=1dϕi
  2. L2 范数: ∑i=1dϕi2\sqrt{\sum_{i=1}^{d} \phi_i^2}i=1dϕi2
  3. 最大 SHAP 值: max⁡(ϕ1)\max( \phi_1)max(ϕ1)

  1. 计算 SHAP 重要性示例

计算 L2 范数作为整体特征贡献

shap_feature_importance = np.linalg.norm(shap_values, axis=1)

计算特征的绝对 SHAP 均值

shap_feature_importance = np.mean(np.abs(shap_values), axis=1)

找出贡献最大的维度

top_k_dims = np.argsort(np.abs(shap_values), axis=1)[:, -3:]

  1. 总结

7. 总结

SHAP 方法 适用模型 计算复杂度 优点 缺点
经典 SHAP 计算 任何模型 ( O(2^n) ) 精确计算 Shapley 值,理论最优 计算量指数级增长,无法用于高维数据
Deep SHAP 深度学习(CNN, RNN, Transformer) ( O(n) ) 适用于神经网络,支持梯度计算 依赖于选定的基线数据,解释可能受基线选择影响
Kernel SHAP 任何模型(黑盒) ( O(n^2) ) 适用于任何模型,无需访问模型内部 计算较慢,高维数据开销大
Tree SHAP 决策树(XGBoost, LightGBM) ( O(TL) ) 计算高效,支持任意树模型 仅适用于树模型,无法用于 DNN
L2 范数聚合 处理嵌入特征 ( O(d) ) 适用于高维嵌入特征,衡量整体贡献 不能解释具体维度贡献,仅提供整体影响
最大 SHAP 绝对值 处理嵌入特征 ( O(d) ) 捕捉最重要维度贡献 可能忽略次要维度的影响

这篇 Markdown 代码 适用于 CSDN、Jupyter Notebook、GitHub Markdown 编辑器,确保公式和代码格式正确展示!🚀

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐