multi-class 的 SHAP 值解释

SHAP values interpretation for multi-class

我正在查看 Iris 数据集,我在其中为我的 X_test 数据集计算了 SHAP_values,我提供了每个数组的前五个作为示例:

    [
        array([[-0.02994951, -0.00631915, -0.11904487, -0.13368648],
               [-0.00344951,  0.06718085,  0.24445513,  0.40281352],
               [-0.02701866, -0.00925   , -0.084     , -0.16873134],
               [-0.02994951, -0.00631915, -0.11904487, -0.13368648],
               [-0.03526866, -0.001     , -0.11904487, -0.13368648]]), 
    
        array([[ 0.02296024,  0.0191085 ,  0.27049242,  0.31693884],
               [ 0.02209713, -0.0431662 , -0.12745271, -0.20947822],
               [-0.0270254 , -0.0025275 , -0.10235476, -0.22609234],
               [ 0.03241468,  0.04532274,  0.25367799,  0.29808459],
               [ 0.04827892, -0.00105323,  0.13303134,  0.36174298]]), 
        
        array([[ 0.00698927, -0.01278935, -0.15144755, -0.18325236],
               [-0.01864762, -0.02401465, -0.11700243, -0.1933353 ],
               [ 0.05404406,  0.0117775 ,  0.18635476,  0.39482368],
               [-0.00246517, -0.03900359, -0.13463313, -0.16439811],
               [-0.01301026,  0.00205323, -0.01398647, -0.2280565 ]])
    ]

我有以下预期值:

EV = [0.289 0.358 0.353]

例如,对于数组 0 中的第一行,我已将期望值添加到数组 0 中的行 0 的总和中,然后我可以查看给定样本的贡献加起来是 0 还是 1 .

sv_0_sum = sv_0.iloc[0, :] # -0.28900000000000003
print(sv_0_sum.sum() + explainer.expected_value[0])

在这种情况下结果为 0。我认为这是有道理的,但是使用二进制 classification,SHAP 值将导致 2 个数组,其中反映了值。举个例子,给定某个数据集中一个样本的任意值是:

shap_values[0] = [0.013, 0.423, 0.245, -0.0123] 

shap_values[1] = [-0.013, -0.423, -0.245, 0.0123] 

但是这个概念如何与 multi-class 一起使用?在为 Iris 提供的三个数组中,我没有得到这种反射,那么我如何理解 multi-class 情况下输出的 SHAP 值?

让我们尝试重现:

from lightgbm import LGBMClassifier
from shap.datasets import iris
from shap import Explainer, Explanation
from shap import waterfall_plot
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(*iris(), random_state=42)
model = LGBMClassifier().fit(X_train, y_train)
explainer = Explainer(model)
sv = np.array(explainer.shap_values(X_test))  # <-- SHAP values
ev = np.array(explainer.expected_value)       # <-- base values

您在这里得到的是每个 class:

的基础值
ev

array([-3.5596808 , -1.08989253, -3.20879218])

您将在其上添加形状值。注意形状:

ev.shape, sv.shape

((3,), (3, 38, 4))

其中:

  • 3对应的数量是classes
  • 38到例数
  • 4 是特征,您有兴趣为其查找 SHAP 值。

那么,您可能会对如何解释特定预测感兴趣:

idx = 0
model.predict(X_test.iloc[[idx]], raw_score=True)

array([[-8.10103813,  1.50946338, -3.6985032 ]]) 

如果将每个感兴趣数据点的 SHAP 值添加到基值,您将获得相同的预测值:

ev + sv[:, idx, :].sum(-1) 

array([-8.10103813,  1.50946338, -3.6985032 ])

或视觉上:

waterfall_plot(Explanation(sv[0][idx], ev[idx], feature_names=X_train.columns))

其中 0 代表感兴趣的 class 预测。

PS

由于 LGBM classifier 内置的随机性,您很可能会得到略有不同的结果。