bar plot

本 notebook 旨在演示(并因此记录)如何使用 shap.plots.bar 函数。它使用在经典的 UCI 成人收入数据集上训练的 XGBoost 模型(这是一个分类任务,用于预测 90 年代人们的收入是否超过 5 万美元)。

[1]:
import xgboost

import shap

# train XGBoost model
X, y = shap.datasets.adult(n_points=2000)
model = xgboost.XGBClassifier().fit(X, y)

# compute SHAP values
explainer = shap.Explainer(model, X)
shap_values = explainer(X)

全局条形图

将 SHAP 值矩阵传递给条形图函数会创建一个全局特征重要性图,其中每个特征的全局重要性被认为是该特征在所有给定样本上的平均绝对值。

[2]:
shap.plots.bar(shap_values)
../../../_images/example_notebooks_api_examples_plots_bar_3_0.png

默认情况下,条形图最多只显示十个条形,但这可以通过 max_display 参数来控制

[3]:
shap.plots.bar(shap_values, max_display=12)
../../../_images/example_notebooks_api_examples_plots_bar_5_0.png

局部条形图

将一行 SHAP 值传递给条形图函数会创建一个局部特征重要性图,其中条形是每个特征的 SHAP 值。 请注意,特征值以灰色显示在特征名称的左侧。

[4]:
shap.plots.bar(shap_values[0])
../../../_images/example_notebooks_api_examples_plots_bar_7_0.png

队列条形图

传递 Explanation 对象的字典将创建一个多条形图,每种条形类型代表由 explanation 对象表示的队列之一。下面我们使用它来分别绘制男性和女性的特征重要性全局摘要。

[5]:
sex = ["Women" if shap_values[i, "Sex"].data == 0 else "Men" for i in range(shap_values.shape[0])]
shap.plots.bar(shap_values.cohorts(sex).abs.mean(0))
../../../_images/example_notebooks_api_examples_plots_bar_9_0.png

我们还可以使用 Explanation 对象的自动队列特征,使用决策树创建一组队列。调用 Explanation.cohorts(N) 将创建 N 个队列,这些队列使用 sklearn DecisionTreeRegressor 最佳地分隔实例的 SHAP 值。 如果我们对成人人口普查数据执行此操作,那么我们将看到资本收益低与资本收益高的人之间存在明显的差异。 请注意,括号中的数字是每个队列中的实例数。

[6]:
shap.plots.bar(shap_values.cohorts(2).abs.mean(0))
../../../_images/example_notebooks_api_examples_plots_bar_11_0.png

使用特征聚类

通常,数据集中的特征彼此部分或完全冗余。 其中冗余意味着模型可以使用任一特征并仍然获得相同的准确率。 为了找到这些特征,从业人员通常会计算特征之间的相关矩阵,或使用某种类型的聚类方法。 当使用 SHAP 时,我们建议采用更直接的方法,通过模型损失比较来衡量特征冗余。 shap.utils.hclust 方法可以做到这一点,并通过训练 XGBoost 模型来预测每对输入特征的结果来构建特征的层次聚类。 对于典型的表格数据集,这比您从相关性等无监督方法中获得的特征冗余度量要准确得多。

一旦我们计算出这样的聚类,我们就可以将其传递给条形图,以便我们可以同时可视化特征冗余结构和特征重要性。 请注意,默认情况下,我们不显示所有聚类结构,而仅显示距离 < 0.5 的聚类部分。 聚类中的距离被假定大致在 0 到 1 之间缩放,其中 0 距离意味着特征完全冗余,而 1 意味着它们完全独立。 在下面的图中,我们看到只有 relationship 和 marital status 具有超过 50% 的冗余,因此它们是条形图中分组的唯一特征

[7]:
# by default this trains (X.shape[1] choose 2) 2-feature XGBoost models
clustering = shap.utils.hclust(X, y)
shap.plots.bar(shap_values, clustering=clustering)
../../../_images/example_notebooks_api_examples_plots_bar_13_0.png

如果我们想看到更多的聚类结构,我们可以将 clustering_cutoff 参数从 0.5 调整为 0.9。 请注意,当我们增加阈值时,我们会约束特征的排序以遵循有效的聚类叶子排序。 条形图对每个聚类和子聚类特征重要性值在该聚类中进行排序,试图将最重要的特征放在顶部。

[8]:
shap.plots.bar(shap_values, clustering=clustering, clustering_cutoff=0.9)
../../../_images/example_notebooks_api_examples_plots_bar_15_0.png

请注意,某些 explainer 在解释过程中使用聚类结构。 他们这样做既是为了避免在解释模型时以不切实际的方式扰动特征,也是为了计算性能。 当您使用这些方法计算 SHAP 解释时,它们会附带 Explanation 对象中包含的聚类。 当条形图找到这样的聚类时,它会使用它,而无需您显式地通过 clustering 参数传递它

[9]:
# only model agnostic methods support shap.maskers.TabularPartitions right now so we wrap our model as a function
def f(x):
    return model.predict(x, output_margin=True)


# define a partition masker that uses our clustering
masker = shap.maskers.Partition(X, clustering=clustering)

# explain the model again
explainer = shap.Explainer(f, masker)
shap_values_partition = explainer(X[:100])
[10]:
shap.plots.bar(shap_values_partition)
../../../_images/example_notebooks_api_examples_plots_bar_18_0.png
[11]:
shap.plots.bar(shap_values_partition, clustering_cutoff=2)
../../../_images/example_notebooks_api_examples_plots_bar_19_0.png
[12]:
shap.plots.bar(shap_values_partition[0], clustering_cutoff=2)
../../../_images/example_notebooks_api_examples_plots_bar_20_0.png

有更多有用的示例的想法吗? 欢迎提出拉取请求以添加到此文档 notebook!