Machine learning 为什么在TreeExplainer中包含训练数据时会得到不同的期望值?

Machine learning 为什么在TreeExplainer中包含训练数据时会得到不同的期望值?,machine-learning,scikit-learn,shap,Machine Learning,Scikit Learn,Shap,将训练数据包含在SHAP TreeExplainer中会在scikit learn GBT回归器中给出不同的期望值 可复制示例(在Google Colab中运行): 从sklearn.datasets导入进行回归 从sklearn.model\u选择导入列车\u测试\u拆分 从sklearn.employ导入梯度boosting回归器 将numpy作为np导入 导入形状 形状。\u版本__ # 0.37.0 十、 y=进行回归(n_样本=1000,n_特征=10,随机状态=0) X_序列,X_测

将训练数据包含在SHAP TreeExplainer中会在scikit learn GBT回归器中给出不同的
期望值

可复制示例(在Google Colab中运行):

从sklearn.datasets导入进行回归
从sklearn.model\u选择导入列车\u测试\u拆分
从sklearn.employ导入梯度boosting回归器
将numpy作为np导入
导入形状
形状。\u版本__
# 0.37.0
十、 y=进行回归(n_样本=1000,n_特征=10,随机状态=0)
X_序列,X_测试,y_序列,y_测试=序列测试分割(X,y,测试大小=0.2,随机状态=42)
gbt=梯度增强回归器(随机状态=0)
gbt.fit(X_系列、y_系列)
#平均预测:
平均预测值gbt=np.平均值(gbt.预测值(X列车))
平均值
# -11.534353657511172
#无数据解释者
gbt_解释者=形状树解释者(gbt)
gbt\u解释程序。预期值
#数组([-11.53435366])
np.isclose(平均值、解释值、期望值)
#数组([True])
#带训练数据的解释者
gbt_data_explainer=shap.treeeExplainer(model=gbt,data=X_train)#指定特性_扰动不会改变结果
gbt\u数据\u解释程序。预期值
# -23.564797322079635
因此,当包含训练数据
gbt\u data\u explainer.expected\u value
时的期望值与不提供数据时计算的值有很大不同(
gbt\u explainer.expected\u value

当与(明显不同的)各自的
形状值一起使用时,这两种方法都是相加和一致的:

np.abs(gbt\u explainer.expected\u值+gbt\u explainer.shap\u值(X\u列).和(1)-gbt.predict(X\u列)).max()
#真的
np.abs(gbt\u数据解释者.期望值+gbt\u数据解释者.形状值(X\u序列).和(1)-gbt.predict(X\u序列)).max()<1e-4
#真的
但我想知道为什么它们不提供相同的
预期值
,为什么
gbt\u数据解释者。预期值
与预测的平均值如此不同


我在这里遗漏了什么?

显然
shap
在传递
数据时将子集设置为100行,然后在树中运行这些行以重置每个节点的样本计数。因此报告的
-23.5…
是这100行的平均模型输出

数据
被传递给一个
独立的
掩蔽器,该掩蔽器进行子采样:


运行

来自shap导入遮罩
另一个解释者=shap.treeeexplainer(
gbt,
数据=遮罩。独立(X_序列,最大样本=800),
特征扰动=“树路径依赖”
)
另一个解释者。期望值
回到

-11.534353657511172

尽管@Ben在挖掘
数据如何通过
独立的
掩蔽器方面做了大量工作,但他的回答并没有准确地说明(1)如何计算基值以及从何处获得不同的基值,以及(2)如何选择/降低
最大样本
参数

不同值的来源

遮罩对象具有一个
data
属性,该属性保存遮罩处理后的数据。要获取gbt\U解释程序中显示的值,请执行以下操作:

从shap.maskers独立导入
gbt=梯度增强回归器(随机状态=0)
#平均预测:
平均预测值gbt=np.平均值(gbt.预测值(X列车))
平均值
# -11.534353657511172
#无数据解释者
gbt_解释者=形状树解释者(gbt)
gbt\u解释程序。预期值
#数组([-11.53435366])
gbt\U解释者=形状树解释者(gbt,独立(X\U系列,100))
gbt\u解释程序。预期值
# -23.56479732207963
我们需要做到:

masker=独立(X_系列,100)
gbt.predict(masker.data).mean()
# -23.56479732207963
如何选择
最大样本数

max_samples
设置为原始数据集长度似乎也适用于其他解释者:

导入sklearn
从sklearn.feature\u extraction.text导入TfidfVectorizer
从sklearn.model\u选择导入列车\u测试\u拆分
导入形状
从shap.maskers导入独立的
从scipy.special import logit导出
语料库,y=shap.datasets.imdb()
语料库训练,语料库训练,y训练,y训练=训练训练测试分割(语料库,y,测试大小=0.2,随机状态=7)
矢量器=TFIDF矢量器(最小值为10)
X_序列=矢量器。拟合变换(语料库序列)
模型=sklearn.线性模型.逻辑回归(惩罚=“l2”,C=0.1)
模型拟合(X\U系列、y\U系列)
解释者=形状解释者(模型
,遮罩=独立(X_系列,100)
,feature_names=vectorizer.get_feature_names()
)
explainer.expected_值
# -0.18417413671991964
该值来自:

masker=独立(X_系列,100)
logit(model.predict_proba(masker.data.mean(0).重塑(1,-1))[…,1])
#数组([-0.18417414])
max_samples=100
对于
true
base_值来说似乎有点不合适(仅馈电功能意味着):

logit(model.predict_proba(X_train.mean(0)。重塑(1,-1))[:,1])
数组([-0.02938039])
通过增加
max_samples
可以合理地接近
true
基线,同时保持较低的样本数:

masker=独立(X_系列,1000)
logit(model.predict_proba(masker.data.mean(0).重塑(1,-1))[:,1])
# -0.05957302658674238
因此,要获得感兴趣的解释者的基值(1)通过模型传递
explainer.data
(或
masker.data
),以及(2)选择
max_samples
,以便采样数据的基值足够接近真实的基值。您还可以尝试观察形状重要性的值和顺序是否收敛

有些人可能会注意到,为了获得基本值,有时我们会平均特征输入(
LogisticRegression
),有时会平均输出(