代码下载

点击此处下载代码


原文链接 https://towardsdatascience.com/shap-explain-any-machine-learning-model-in-python-24207127cad7

想象一下,你正试图训练一个机器学习模型来预测广告是否被特定的人点击。在收到关于某人的一些信息后,模型预测某人会不会点击广告。

但是为什么模型会输出这样的预测结果呢? 每个特征对预测的贡献有多大? 如果您能看到一个图表,显示每个特征对预测的贡献程度,如下所示,不是很好吗?

Shapley值就能起到特征权重测度的作用。

Shapley值是什么?

Shapley值是博弈论中使用的一种方法,它涉及公平地将收益和成本分配给在联盟中工作的行动者。 由于每个行动者对联盟的贡献是不同的,Shapley值保证每个行动者根据贡献的多少获得公平的份额。

小案例

Shapley值被广泛地应用于求解群体中每个工人(特征)的贡献问题。要理解Shapley值的作用,让我们想象一下贵公司刚刚做了A/B测试,他们在测试广告策略的不同组合。

每个策略在特定月份的收入是:

  • 无广告:150美元
  • 社交媒体:300美元
  • 谷歌广告:200美元
  • 电子邮件营销:350美元
  • 社交媒体和谷歌广告:320美元
  • 社交媒体和电子邮件营销:400美元
  • 谷歌广告和电子邮件营销:350美元
  • 电子邮件营销,谷歌广告和社交媒体:450美元

使用三则广告与不使用广告的收入相差300美元,每则广告对这一差异有多大的贡献?

我们可以通过计算每一类广告的Shapley值来计算谷歌广告对公司收入的总贡献入手,通过公式可以计算出Google广告的总贡献:

让我们找到Google广告的边际贡献及其权重。

寻找谷歌广告的边际贡献

第一,我们将发现谷歌广告对以下群体的边际贡献:

  • 无广告
  • 谷歌广告+社交媒体
  • 谷歌广告+电子邮件营销
  • 谷歌广告+电子邮件营销+社交媒体

Google广告 对 无广告 的边际贡献是:

谷歌广告 对 谷歌广告&社交媒体组合 的边际贡献是:

谷歌广告 对 谷歌广告&电子邮件营销组合 的边际贡献是:

谷歌广告 对 谷歌广告、电子邮件营销和社交媒体组合 的边际贡献是:

发现权重

为了发现权重,我们将把不同广告策略的组合组织成如下多个层次,每个层次对应于每个组合中广告策略的数量。

然后根据每个层次的边数分配权重,我们看到了这一点:

  • 第一级包含3条边,因此每个边的权重为1/3
  • 第二级包含6条边,因此每条边的权重将为1/6
  • 第三级包含3条边,因此每条边的权重将为1/3

发现Google广告的总贡献

根据前面的权重和边际贡献,我们已经可以找到Google广告的总贡献!

酷!所以谷歌广告在使用3种广告策略与不使用广告的总收入差异中贡献了36.67美元。36.67是Google广告的Shapey值。

重复以上步骤,对于另外两种广告策略,我们可以看出:

  • 电子邮件营销贡献151.67美元

  • 社交媒体贡献116.67美元

  • 谷歌广告贡献36.67美元

他们共同出资300美元,用于使用3种不同类型的广告与不使用广告的区别!挺酷的,不是吗? 既然我们理解了Shapley值,那么让我们看看如何使用它来解释机器学习模型。

SHAP-在Python中解释机器学习模型

SHAP是一个Python库,它使用Shapley值来解释任何机器学习模型的输出。

安装SHAP


!pip3 install shap

训练模型

为了理解SHAP工作原理,我们使用Kaggle平台内的advertising广告数据集。

import pandas as pd 

df = pd.read_csv("advertising.csv")
df.head()

我们将建立一个机器学习模型, 该模型根据用户个人特质信息来预测其是否点击广告。

我们使用Patsy将DataFrame转换为一组特征和一组目标值:

from patsy import dmatrices
from sklearn.model_selection import train_test_split

y, X = dmatrices(
    "clicked_on_ad ~ daily_time_spent_on_site + age + area_income + daily_internet_usage  + male -1",
    data=df,
)

X_frame = pd.DataFrame(data=X, columns=X.design_info.column_names)


把数据分为测试集和训练接

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=7)

接下来使用XGBoost训练模型,并做预测

import xgboost
model = xgboost.XGBClassifier().fit(X_train, y_train)
y_predicted = model.predict(X_test)

为了查看模型表现,我们使用F1得分

from sklearn.metrics import f1_score

f1 = f1_score(y_test, y_predicted)
f1
0.9619047619047619

太好了!

解释该模型

该模型很好地预测了用户是否点击广告。但它是如何得出这样的预测的? 每个特征对最终预测与平均预测的差异贡献了多少?

注意,这个问题与我们在文章开头论述的问题非常相似。

因此,寻找每个特征的Shapley值可以帮助我们确定它们的贡献。得到特征i的重要性的步骤与之前类似,其中i是特征的索引:

  • 获取所有不包含特征i的子集
  • 找出特征i对这些子集中每个子集的边际贡献
  • 聚合所有边际贡献来计算特征i的贡献

若要使用SHAP查找Shapley值,只需将训练好的模型插入shap.Explainer

import shap

explainer = shap.Explainer(model)
shap_values = explainer(X_frame)
ntree_limit is deprecated, use `iteration_range` or model slicing instead.

SHAP瀑布图

可视化第一个预测的解释:

#第一条记录是未点击
shap.plots.waterfall(shap_values[0])

啊哈!现在我们知道每个特征对第一次预测的贡献。对上图的解释:

  • 蓝色条显示某一特定特征在多大程度上降低了预测的值。
  • 红条显示了一个特定的特征在多大程度上增加了预测值。
  • 负值意味着该人点击广告的概率小于0.5

我们应该期望总贡献等于预测与均值预测的差值。我们来验证一下:

酷!他们是平等的。

可视化第二个预测的解释:

#第二条记录也是未点击
shap.plots.waterfall(shap_values[1])

SHAP摘要图

我们可以使用SHAP摘要图,而不是查看每个单独的实例,来可视化这些特性对多个实例的整体影响:

shap.summary_plot(shap_values, X)

SHAP摘要图告诉我们数据集上最重要的特征及其影响范围。

从上面的情节中,我们可以对模型的预测获得一些有趣的见解:

  • 用户的 daily_internet_usage 对该用户是否点击广告的影响最大。
  • 随着daily_time_spent_on_site的增加,用户点击广告的可能性降低。
  • 随着area_income的增加,用户点击广告的可能性降低。
  • 随着age的增长,用户更容易点击广告。
  • 如果用户是male,则该用户点击广告的可能性较小。

SHAP条形图

我们还可以使用SHAP条形图得到全局特征重要性图。

shap.plots.bar(shap_values)

很酷!

结论

恭喜你!您刚刚了解了Shapey值以及如何使用它来解释一个机器学习模型。希望本文将提供您使用Python来解释自己的机器学习模型的基本知识。



广而告之