基于XGBoost 的机器学习可解释性

出品:贪心科技(公众号:贪心科技)

作者:Scott Lundberg


前言

本篇讲述了机器学习模型解释不当的危害和正确解读的价值。如果你发现ensemble tree 算法(比如梯度提升机器,或者随机森算法)的鲁棒精度很有意思,但同时还想解读他们,我希望本文章能够提供有用的信息。


设想一下,我们的任务是为为一家银行预测个人的财务状况。我们的算法越精准,银行赚的钱越多。但由于这个预估也会被用来做借贷申请,所以法律上我们也要求提供一份解释说明如何做出预测。经过多种算法的测试,我们发现使用XGBoost的梯度提升树算法最准确。不过要解释XGBoost能够做出准确的预测的原因比较难,所以我们只剩下两个选择,退回到直线算法或者查明怎样能够解读我们的XGBoost 模型。没有一个数字科学家会放弃对准确度的追求,所以我们决定尝试后者, 解读复杂的XGBoost 模型(总共1247 个深度,6 个树状)。



传统的全局特征重要性度量方法


第一个明显的选择是在Python XGBoost 界面使用Plot_importance() 方法。 它能够给出吸引人的价单图表,用于表示我们数据集中的每个特种的重要性:(文章中图表的CODE可点击 链接Jupyter notebook) 

运行xgboost.plot_importance 算法从人口普查数据集中的“成人”类别中预估人们是否会上报超过5万美金的收入(使用损失函数)

如果我们看一下XGBoost 返回的特征重要性, 我们能发现“年龄”占主导地位, 也是影响收入的最明显的因素。我们可以在这停下来,然后告诉我们的经理一个我们自己觉得比较满意的答案,年龄是最重要的因素,然后是每周的工作时间和教育水平。但是作为一个优秀的数据可选家,再看一下文件,就会发现有XGBoost 中有三个选项用来衡量特征重要性:

  •  权重(Weight): 指的是一个特征在整个树状中被用来分割的次数。

  • 覆盖(Cover): 指的是一个特征在整个树状中被用来分割的次数被加权于所有经过这些分割的训练数据点的次数

  • 增益(Gain):当使用特征分割时,平均训练损失的减少值


这些是我们在任何树型算法包中都可能发现的典型的重要性度量值。权重是默认选项,所以我们决定使用另外两个方法做个尝试,看看是否结果会不同。

运行xgboost.plot_importance with both importance_type=”cover” and importance_type=”gain”的结果

让我们吃惊的是,我们发现XGBoost 根据这三个选项分别提供的特种重要性排序大为不同。通过覆盖法,资本收益看起来是最具预测性的,然而通过增益法,关系状况是主导。这让我们这些依赖于这些方法来报告特种重要性但是又不知道那种方法最好的人非常不安。



什么决定特征重要性的标准是好是坏?


单单对比一个特征归因法同另一个是不够明显的,我们可以测量每个任务的最终用户性能, 比如数据清洗,偏流检波等等。但是这些任务只是对特征属性方法的质量的间接度量。在这里,我们将定义两个属性,我们认为任何好的特征归因方法都应该遵循:

  • 一致性:无论何时我们更改一个更多的依赖于某特性的模型,该特性属性重要性不会减少。

  •  精确性:所有特征重要性的总和应归结为模型的总重要性。(例如,如果重要性是由R值来标识的,那么每个特征的属性应该与整个模型的R值相加。)


如果一致性不成立,那么我们不能比较任何两个模型之间的属性特征重要性,因为具有较高的分配属性并不意味着模型实际上更多地依赖于该特征。


如果精度不能保持,那么我们不知道每个特征的属性如何组合来表示整个模型的输出。我们不能仅仅在方法完成之后对属性进行归一化,因为这可能会破坏方法的一致性。



现有的归因法是否一致和精确?


回到我们作为银行数据科学家的工作……我们认识到一致性和准确性对我们很重要。事实上,如果一个方法不一致,我们不能保证具有最高属性的特征实际上是最重要的。因此,我们决定使用两个非常简单的树模型来检查每个方法的一致性,这些模型与我们在银行的任务无关:

两个特征的简单树模型。咳嗽在模型B中明显比A型更重要。

模型的输出是基于一个人的症状的风险评分。模型A只是一个简单的“和”功能的二进制特征”发热“和”咳嗽“。B型是相同的函数,但每次咳嗽时都是+10。为了检验一致性,我们必须定义“重要性”。在这里,我们将定义两种重要方式:1)当我们移除一组特征时模型中预计精准度的变化。2)当我们移除一组特征时模型预期输出的变化。


重要性的第一个定义测量了特征对模型的全局影响。而第二个定义测量了特征对单个预测的个性化影响。在我们简单的树模型中,咳嗽特征在B模型中显然更为重要,无论是对于全局的重要性还是在发热和咳嗽都是肯定的情况下对个体预测的重要性。


上述权重、覆盖和增益方法都是全局特征属性的方法。但是,当我们在银行中部署我们的模型时,我们也需要对每个客户进行个性化的解释。为了检查一致性,我们在简单的树模型上运行了六种不同的特征属性方法:

  • Tree SHAP: 一个我们新提出的个性化方法

  • Saabas: 一种个性化启发式特征归因方法。

  • 均值(Mean) (Tree SHAP) :一种基于个体化树SAP属性平均大小的全局属性方法。

  • 增益(Gain): 在XGBoost中使用的相同方法,也相当于在SCIKIT中使用的基尼重要度量树模型。

  • 分裂计数(Split Count)在XGBoost中代表了密切相关的“权重”和“覆盖”方法,但使用“权重”方法计算

  • 置换(Permutation):当单个特征在测试数据集中随机置换时,模型的精度下降。

模型A和B模型的特征归因采用六种不同的方法。我们可以看出,这些方法代表了文献中所有的树特定的特征归因方法。

除了特征排列之外,以前所有的方法都是不一致的!这是因为他们在模型B对咳嗽的重要性的分配少于A模型。一个不一致的方法不能被采用, 因为他不能准确的将最终要的影响特征赋予更多的重要性。聪明的读者会注意到,这种不一致性早就在在我们传统的特征归因法中显现出来,因为当我们检查时,传统的特征归因方法在同一模型上是相互矛盾的。精度特性如何?事实证明,Tree SHAP、Sabaas和增益因为定义的早,所以是精确的,而特征置换和分裂计数不是。


令人惊讶的是,这种广泛使用的增益(基尼重要度)方法会导致这种明显的不一致结果。为了更好地理解为什么会发生这种情况,让我们检查模型A和模型B的增益是如何计算的。为了简化这一点,我们假设我们的数据集的25%落入每个叶中,并且每个模型的数据集都具有与模型输出精确匹配的标签。


如果我们考虑均方误差(MSE)作为我们的损失函数,那么我们在模型A中做任何分裂之前以MSE为1200开始,这是从20的常数平均预测中得到的误差。在模型A中的发热特征分裂后,MSE下降到800,因此增益法将此下降400归因于发热特征。在咳嗽特征上再次分裂然后导致MSE为0,增益法将此下降800归因于咳嗽特征。在模型B中,相同的过程导致分配给发烧特征的重要性为800,咳嗽特征为625.

增益计算(AKA)Gini的重要性),模型A和B模型的得分。

通常我们认为Tree的根附近的特征比叶子附近的特征更重要(因为树木被贪婪地构造)。然而,增益方法被偏向于更重要的是低端分裂。这种偏倚导致不一致性,当咳嗽变得更重要时(因此它在根部分裂),其归因重要性实际上下降。个体化的Saabas方法(由treeinterpreter程序包使用)计算我们对Tree进行进一步拆分时的预测差异,因此它也遭受朝Tree 下方分裂时同样的偏差。随着树木越来越深,这种偏向只会增加。相比之下 Tree SHAP方法相当于对所有特征可能分类的预测的差异进行数字化平均,而不只是根据他们在树中的位置进行指定的排序。


Tree SHAP的一致性和准确性并不是巧合。考虑到我们想要一种既一致又准确的方法,结果只有一种方法来分配特征重要性。细节发布在我们的NIPS论文中的,但总结以下就是,从游戏理论的利润公平分配的证明可以引出机器学习中特征归因法的一个独特结果。这些独特的值被称为Shapley值。这是在五十年代Loyd Shapley 将这些值导出之后命名的。这里使用的SHAP值是由众多单个同Shapley 值相关的的模型解释法统一而形成的。Tree SHAP是一种快速算法,可以精确地计算树在多项式时间内而不是传统的指数运行时间的SHAP值。




有信心地解读我们的模型


坚实的理论证明和快速实用的算法相结合,使SHAP值成为一个强大的工具,可以用来自信地解释树模型,如XGBoost的梯度提升机器。


有了这个新的方法,我们可以回到解读我们的银行XGBoost模型的任务中来:

全局均值法((|Tree SHAP|)应用于收入预测模板。

当一个特征从模型中被隐藏时,X轴基本上是模型输出中的平均幅度变化(对于这个模型,输出具有对数概率单位)。请参阅论文以获取详细信息,但“隐藏”意味着将变量从模型中集成。由于隐藏特征变化的影响取决于隐藏的其他特征,因此使用Shapley值能强化一致性和准确性。


我们可以看到,关系特征实际上是最重要的,其次是年龄特征。由于SHAP值保证了一致性,所以我们不必担心在使用增益或分立计数方法之前发现的各种矛盾。然而,既然我们现在对每个人都有个性化的解释,我们可以做的不仅仅是制作一张条形图。我们可以为我们数据库中的每个客户绘制特征重要性。SHAP Python程序包使得这很容易。我们首先调用shap.TreeExplainer(model).shap_values(X)

来解释每个预测;

然后调用shap.summary_plot(shap_values, X)

来绘制这些解释:

每一位顾客在每一行都有一个点。

点的X位置是模型对客户的预测的影响的特征,并且点的颜色表示该特征对于客户的价值。不适合行的点堆积显示密度(在这个例子中有32561个客户)。由于XGBoost模型具有逻辑损耗,X轴具有对数几率的单位(Tree SHAP解释模型的边距输出的变化)。


这些特征用mean(|Tree SHAP|)排序,因此我们再次看到关系特征是年收入超过5万美元的最强预测因素。通过绘制一个特征对每个样本的影响,我们也可以看到重要的离群效应。例如,虽然资本增益不是全球最重要的特征,但它是迄今为止客户子集的最重要特征。特征值的颜色显示了我们的模式,比如年轻人如何降低个人赚取的机5万会,而高等教育如何增加了个人赚取超过5万美金的机会。


我们可以在这里停下来向老板展示这一图表,但是让我们深入研究一下这些特征。我们可以通过绘制年龄SHAP值(对数赔率的变化)与年龄特征值来为年龄特征做以下工作:

Y轴是年赚取超过5万美金的对数赔率对年龄特征的改变,X轴是顾客的年龄。每个点代表来自数据集的单个客户。

在这里,我们看到由XGBoost 模型捕捉到的年龄对盈利潜力的明显影响。注意,不同于传统的部分依赖图(它显示了在改变特征值时的平均模型输出),这些SHAP依赖图显示了交互作用。尽管数据集中的许多人都是20岁,但是他们的年龄对他们的预测的影响,像20岁的垂直分散点所显示的, 是大为不同的。这意味着其他特征正在影响年龄的重要性。为了了解什么特征影响了这部分,我们根据教育年限将这些点涂上颜色,然后我们发现高水平的教育降低了一个人20多岁时年龄的影响,但增大了30多岁时年龄的影响。

Y轴是年赚取超过5万美金的对数赔率对年龄特征的改变。X轴是顾客的年龄。教育数是客户完成的教育年限。

如果我们对每周工作的小时数做出另一种依赖性曲线图,我们就会发现在大约每周工作五十小时得到的工作好处越平稳, 而且如果你结婚了,额外的工作不太可能表明高收入。

每周工作时间与工作时间数对收入潜力的影响

解读自己的模型


这种简单的攻略本来用于反应你在设计和执行自己模型中可能经历的过程。SHAP包很容易通过PIP安装,我们希望它有助于您有信心地开发您的模型。它包含了比本文所涉及的更多的东西,包括SAP交互值、模型独立SHAP 值评估和额外的可视化。笔记本可用于说明各种有趣的数据集上的所有这些特征。例如,你可以使用死亡率的XGBoost 模型,根据笔记本上的健康检查来找出你可能死亡的主要原因。对于Python以外的语言,Tree SHAP也被直接合并到核心XGBoost和LightGBM包中。


如果对本文有自己的见解,欢迎在评论区留言,   或者扫码关注公众号交流。



此为贪心科技编译,转载请联系本公众号获得授权。


阅读更多

没有更多推荐了,返回首页