【发布时间】:2020-11-13 13:30:05
【问题描述】:
在 SHAP TreeExplainer 中包含训练数据会在 scikit-learn GBT Regressor 中给出不同的expected_value。
可重现的示例(在 Google Colab 中运行):
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingRegressor
import numpy as np
import shap
shap.__version__
# 0.37.0
X, y = make_regression(n_samples=1000, n_features=10, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
gbt = GradientBoostingRegressor(random_state=0)
gbt.fit(X_train, y_train)
# mean prediction:
mean_pred_gbt = np.mean(gbt.predict(X_train))
mean_pred_gbt
# -11.534353657511172
# explainer without data
gbt_explainer = shap.TreeExplainer(gbt)
gbt_explainer.expected_value
# array([-11.53435366])
np.isclose(mean_pred_gbt, gbt_explainer.expected_value)
# array([ True])
# explainer with training data
gbt_data_explainer = shap.TreeExplainer(model=gbt, data=X_train) # specifying feature_perturbation does not change the result
gbt_data_explainer.expected_value
# -23.564797322079635
因此,包含训练数据 gbt_data_explainer.expected_value 时的预期值与未提供数据时计算的预期值 (gbt_explainer.expected_value) 完全不同。
当与(明显不同的)各自的shap_values 一起使用时,这两种方法都是相加且一致的:
np.abs(gbt_explainer.expected_value + gbt_explainer.shap_values(X_train).sum(1) - gbt.predict(X_train)).max() < 1e-4
# True
np.abs(gbt_data_explainer.expected_value + gbt_data_explainer.shap_values(X_train).sum(1) - gbt.predict(X_train)).max() < 1e-4
# True
但我想知道为什么他们不提供相同的expected_value,以及为什么gbt_data_explainer.expected_value 与预测的平均值如此不同。
我在这里错过了什么?
【问题讨论】:
-
部分解释:尝试从
gbt_data_explainer提取解释失败并显示有用的消息。运行gbt_explainer.model.fully_defined_weighting, gbt_data_explainer.model.fully_defined_weighting会得到True, False:shap 认为X_train不会到达每棵树的每一片叶子。 -
代码的相关位:github.com/slundberg/shap/blob/… 我不知道为什么 shap 会使用它的 C 代码得到不同的预测 (github.com/slundberg/shap/blob/…); sklearn 在中点(特征值之间)分裂,所以我不认为舍入错误是罪魁祸首。
-
这是我基于半小时研究的最佳选择。这个解释还有很多问题:为什么TreeExplainer对
feature_perturbation参数不敏感?它是一个错误吗? TreeExplainer 真的是一种精确的形状值估计方法吗?如果是背景数据,需要多少样本才能获得准确的结果? -
到达那里:
gbt_explainer.data.shape只是(100, 10)...但我找不到它在代码中的哪个位置(下采样?)。因此,当它执行先前链接的步骤“如果给定数据,则重新计算通过每个节点的样本数”时,它没有整个集合,并且无法填充所有叶子,如前所述。另见解释者的.model.node_sample_weight列表。
标签: machine-learning scikit-learn shap