器→工具, 工具软件, 开源项目, 数据, 术→技巧

机器学习可解释性工具:SHAP

钱魏Way · · 6 次浏览

机器学习在很多领域取得了重要的进步,也帮助人减少了不少体力劳动。要训练一个机器学习模型,以及将模型应用在实际场景中,最重要的是数据的收集以及处理。那么,如何使用模型指导数据收集就成了一个重要的问题,因为搞清楚这个问题,可以让“人工智能”的“人工”部分聚焦在重要的维度,事半功倍。另外,对于一个模型,它是否符合原本对它的预期,也是在考察模型效果时的一个需要考虑的因素。换句话说,一个模型对于一个特定的样本,哪一些特征起到的决定性作用;再换句话说,当面对老板的“灵魂拷问”时,如何跟他解释他关注的样本没得到更好的效果的原因。所以,模型可解释性的两层重要的意义:

  • 指导业务:模型中的那些特征最重要,使用模型指导业务
  • 解释case:解释对特定案例,是哪个特征造成效果的好与不好

在众多模型中,可解释性最强的当然是线性模型;但是由于线性模型在特征提取方面存在天然的弱势,以及过于依赖原始的特征工程,在稍微复杂一些的场景中,基本见不到线性模型的影子。现在效果比较好的几类模型,tree based模型和neural network模型可获得较好的效果,但他们同时也被称为“黑盒”模型。原因是对于这类模型来说,上面的两点应用很难实现。所以,打开“黑盒”模型就成了一个值得研究的课题。

机器学习模型的可解释性

机器学习业务应用以输出决策判断为目标。可解释性是指人类能够理解决策原因的程度。机器学习模型的可解释性越高,人们就越容易理解为什么做出某些决定或预测。模型可解释性指对模型内部机制的理解以及对模型结果的理解。其重要性体现在:

  • 建模阶段,辅助开发人员理解模型,进行模型的对比选择,必要时优化调整模型;
  • 在投入运行阶段,向业务方解释模型的内部机制,对模型结果进行解释。比如基金推荐模型,需要解释:为何为这个用户推荐某支基金。

机器学习流程步骤:收集数据、清洗数据、训练模型、基于验证或测试错误或其他评价指标选择最好的模型。第一步,选择比较小的错误率和比较高的准确率的高精度的模型。第二步,面临准确率和模型复杂度之间的权衡,但一个模型越复杂就越难以解释。一个简单的线性回归非常好解释,因为它只考虑了自变量与因变量之间的线性相关关系,但是也正因为如此,它无法处理更复杂的关系,模型在测试集上的预测精度也更有可能比较低。而深度神经网络处于另一个极端,因为它们能够在多个层次进行抽象推断,所以他们可以处理因变量与自变量之间非常复杂的关系,并且达到非常高的精度。但是这种复杂性也使模型成为黑箱,我们无法获知所有产生模型预测结果的这些特征之间的关系,所以我们只能用准确率、错误率这样的评价标准来代替,来评估模型的可信性。

事实上,每个分类问题的机器学习流程中都应该包括模型理解和模型解释,下面是几个原因:

  • 模型改进:理解指标特征、分类、预测,进而理解为什么一个机器学习模型会做出这样的决定、什么特征在决定中起最重要作用,能让我们判断模型是否符合常理。一个深度的神经网络来学习区分狼和哈士奇的图像。模型使用大量图像训练,并使用另外的一些图像进行测试。90%的图像被准确预测,这值得我们高兴。但是在没有计算解释函数 ( explainer function ) 时,我们不知道该模型主要基于背景:狼图像通常有一个下雪的背景,而哈士奇的图像很少有。所以我们不知不觉地做了一个雪地探测器,如果只看准确率这样的指标,我们就不会看到这一点。知道了模型是如何使用特征进行预测的,我们就能直觉地判断我们的模型是否抓住了有意义的特征,模型是或否能泛化到其他样本的预测上。
  • 模型可信性与透明度:理解机器学习模型在提高模型可信度和提供审视预测结果透明度上是非常必要的,让黑箱模型来决定人们的生活是不现实的,比如贷款和监狱刑法。另一个对机器学习结果可信度提出质疑的领域是药品,模型结果会直接决定病人的生与死。机器学习模型在区分恶性肿瘤和不同类型的良性肿瘤方面是非常准确的,但是我们依然需要专家对诊断结果进行解释,解释为什么一个机器学习模型将某个患者的肿瘤归类为良性或恶性将大大帮助医生信任和使用机器学习模型来支持他们工作。长久来看,更好地理解机器学习模型可以节省大量时间、防止收入损失。如果一个模型没有做出合理的决定,在应用这个模型并造成不良影响之前,我们就可以发现这一点。
  • 识别和防止偏差:方差和偏差是机器学习中广泛讨论的话题。有偏差的模型经常由有偏见的事实导致,如果数据包含微妙的偏差,模型就会学习下来并认为拟合很好。一个有名的例子是,用机器学习模型来为囚犯建议定罪量刑,这显然反映了司法体系在种族不平等上的内在偏差。其他例子比如用于招聘的机器学习模型,揭示了在特定职位上的性别偏差,比如男性软件工程师和女性护士。机器学习模型在我们生活的各个层面上都是强有力的工具,而且它也会变得越来越流行。所以作为数据科学家和决策制定者来说,理解我们训练和发布的模型如何做出决策,让我们可以事先预防偏差的增大以及消除他们,是我们的责任。

可解释性特质:

  • 重要性:了解 “为什么” 可以帮助更深入地了解问题,数据以及模型可能失败的原因。
  • 分类:建模前数据的可解释性、建模阶段模型可解释性、运行阶段结果可解释性。
  • 范围:全局解释性、局部解释性、模型透明度、模型公平性、模型可靠性。
  • 评估:内在还是事后?模型特定或模型不可知?本地还是全局?
  • 特性:准确性、保真性、可用性、可靠性,鲁棒性、通用性等。
  • 人性化解释:人类能够理解决策原因的程度,人们可以持续预测模型结果的程度标示。

可解释性的动机

在工业界中,数据科学或机器学习的主要焦点是更偏 “应用” 的解决复杂的现实世界至关重要的问题,而不是理论上有效地应用这些模型于正确的数据。机器学习模型本身由算法组成,该算法试图从数据中学习潜在模式和关系,而无需硬编码固定规则。因此,解释模型如何对业务起作用总是会带来一系列挑战。有一些领域的行业,特别是在保险或银行等金融领域,数据科学家通常最终不得不使用更传统的机器学习模型 ( 线性或基于树的 )。原因是模型可解释性对于企业解释模型所采取的每个决策非常重要。

残酷的现实是,如果没有对机器学习模型或数据科学 pipeline 如何运作的合理理解,现实中的项目很少成功。现实中的数据科学项目,通常会有业务和技术两方面。数据科学家通常致力于构建模型并为业务提供解决方案。但是,企业可能不知道模型如何工作的复杂细节。

数据科学从业者将知道存在典型的模型可解释性与模型性能权衡。这里需要记住的一点是,模型性能不是运行时或执行性能,而是模型在决策中的准确程度。有几种模型,包括简单的线性模型甚至是基于树的模型,它们可以很容易地解释模型为获得特定的洞察力或预测而做出的决策,但是你可能需要牺牲模型性能,因为它们总是不能产生最好的结果是由于高偏差 ( 线性模型 ) 或高方差的固有问题,导致过度拟合 ( 完全成长的树模型 )。更复杂的模型,如集合模型和最近的深度学习模型系列通常会产生更好的性能,但被认为是黑盒模型,因为很难解释模型如何真正做出决定。

理解模型可解释性

模型解释作为一个概念仍然主要是理论和主观的。任何机器学习模型的核心都有一个响应函数,它试图映射和解释独立 ( 输入 ) 自变量和 ( 目标或响应 ) 因变量之间的关系和模式。当模型预测或寻找见解时,需要做出某些决定和选择。模型解释试图理解和解释响应函数所做出的这些决定,即 what,why 以及 how。模型解释的关键是透明度,质疑能力以及人类理解模型决策的难易程度。模型解释的三个最重要的方面解释如下。

  • 是什么驱动了模型的预测?我们应该能够查询我们的模型并找出潜在的特征交互,以了解哪些特征在模型的决策策略中可能是重要的。这确保了模型的公平性。
  • 为什么模型会做出某个决定?我们还应该能够验证并证明为什么某些关键特征在预测期间驱动模型所做出的某些决策时负有责任。这确保了模型的可靠性。
  • 我们如何信任模型预测?我们应该能够评估和验证任何数据点以及模型如何对其进行决策。对于模型按预期工作的关键利益相关者而言,这应该是可证明且易于理解的。这确保了模型的透明度。

在比较模型时,除了模型性能之外,如果模型的决策比其他模型的决策更容易理解,那么模型被认为比其他模型具有更好的可解释性。

可解释性的重要性

在解决机器学习问题时,数据科学家往往倾向于关注模型性能指标,如准确性,精确度和召回等等 ( 毫无疑问,这很重要 ! )。这在大多数围绕数据科学和机器学习的在线竞赛中也很普遍。但是,指标只能说明模型预测决策的部分故事。随着时间的推移,由于环境中的各种因素导致的模型概念漂移,性能可能会发生变化。因此,了解推动模型采取某些决策的因素至关重要。

如果一个模型工作得很好,为什么还要深入挖掘呢?在解决现实世界中的数据科学问题时,为了让企业信任您的模型预测和决策,他们会不断提出 “我为什么要相信您的模型?” 这一问题,这一点非常有意义。如果一个人患有癌症或糖尿病,一个人可能对社会构成风险,或者即使客户会流失,您是否会对预测和做出决策 ( 如果有的话 ) 感到满意?也许不是,如果我们能够更多地了解模型的决策过程 ( 原因和方式 ),我们可能会更喜欢它。这使我们更加透明地了解模型为何做出某些决策,在某些情况下可能出现的问题,并且随着时间的推移它有助于我们在这些机器学习模型上建立一定程度的信任。

  • 了解预测背后的原因在评估信任方面非常重要,如果计划基于预测采取行动,或者选择是否部署新模型,那么这是至关重要的。
  • 无论人类是直接使用机器学习分类器作为工具,还是在其他产品中部署模型,仍然存在一个至关重要的问题:如果用户不信任模型或预测,他们就不会使用它。

这是我们在本文中多次讨论的内容,也是决定数据科学项目在行业中取得成功的关键区别之一。这推动了模型解释的必要性和重要性的紧迫性。

可解释性的标准

有一些特定的标准可用于分类模型解释方法。Christoph Molnar,2018年 “可解释的机器学习,制作黑箱模型可解释指南” 中提到了一个很好的指南。

  • 内在还是事后?内在可解释性就是利用机器学习模型,该模型本质上是可解释的 ( 如线性模型,参数模型或基于树的模型 )。事后可解释性意味着选择和训练黑匣子模型 ( 集合方法或神经网络 ) 并在训练后应用可解释性方法 ( 特征重要性,部分依赖性图 )。我们将更多地关注我们系列文章中的事后模型可解释方法。
  • 模型特定或模型不可知?特定于模型的解释工具非常特定于内在模型解释方法,这些方法完全依赖于每个模型的功能和特征。这可以是系数,p 值,与回归模型有关的 AIC 分数,来自决策树的规则等等。与模型无关的工具与事后方法更相关,可用于任何机器学习模型。这些不可知方法通常通过分析 ( 和输入的扰动 ) 特征输入和输出对来操作。根据定义,这些方法无法访问任何模型内部,如权重,约束或假设。
  • 本地还是全局?这种解释分类讨论了解释方法是解释单个预测还是整个模型行为?或者如果范围介于两者之间?我们将很快谈论全球和地方的解释。

可解释性的范围

如何定义可解释性的范围和界限?一些有用的方面可以是模型的透明度,公平性和责任性。全局和局部模型解释是定义模型解释范围的明确方法。

  • 全局可解释:就是试图理解 “模型如何进行预测?” 和 “模型的子集如何影响模型决策?”。要立即理解和解释整个模型,我们需要全局可解释性。全局可解释性是指能够基于完整数据集上的依赖 ( 响应 ) 变量和独立 ( 预测变量 ) 特征之间的条件交互来解释和理解模型决策。尝试理解特征交互和重要性始终是理解全球解释的一个很好的一步。当然,在尝试分析交互时,在超过两维或三维之后可视化特征变得非常困难。因此,经常查看可能影响全局知识模型预测的模块化部分和特征子集会有所帮助。全局解释需要完整的模型结构,假设和约束知识。
  • 局部解释:试图理解 “为什么模型为单个实例做出具体决策?” 和 “为什么模型为一组实例做出具体决策?”。对于本地可解释性,我们不关心模型的固有结构或假设,我们将其视为黑盒子。为了理解单个数据点的预测决策,我们专注于该数据点并查看该点周围的特征空间中的局部子区域,并尝试基于该局部区域理解该点的模型决策。本地数据分布和特征空间可能表现完全不同,并提供更准确的解释而不是全局解释。局部可解释模型 – 不可知解释 ( LIME ) 框架是一种很好的方法,可用于模型不可知的局部解释。我们可以结合使用全局和局部解释来解释一组实例的模型决策。
  • 模型透明度:为试图理解 “如何根据算法和特征创建模型?”。我们知道,通常机器学习模型都是在数据特征之上利用算法来构建将输入映射到潜在输出 ( 响应 ) 的表示。模型的透明度可能试图了解模型的构建方式以及可能影响其决策的更多技术细节。这可以是神经网络的权重,CNN 滤波器的权重,线性模型系数,决策树的节点和分裂。但是,由于业务可能不太精通这些技术细节,因此尝试使用不可知的局部和全局解释方法来解释模型决策有助于展示模型透明度。

可解释性的作用

对于想要了解模型如何工作的数据科学家来说,评估模型的准确性通常是不够的。数据科学家通常想知道模型输入变量如何工作以及模型的预测如何根据输入变量的值而变化。

机器学习算法和模型的工程应用中用到最多的主要是树类模型 (lgb, xgb) 和神经网络 (cnn, rnn),使用者往往习惯于很少去思考其中的含义和解释性。需要思考一个模型的哪些东西是可解释的?

所以有几个问题值得讨论:

  • 哪些特征在模型看到是最重要的?
  • 关于某一条记录的预测,每一个特征是如何影响到最终的预测结果的?
  • 从大量的记录整体来考虑,每一个特征如何影响模型的预测的?

为什么这些解释信息是有价值?

  • 调试模型用。一般的真实业务场景会有很多不可信赖的,没有组织好的脏数据。你在预处理数据时就有可能加进来了潜在的错误,或者不小心泄露了预测目标的信息等,考虑各种潜在的灾难性后果,debug 的思路就尤其重要了。当你遇到了用现有业务知识无法解释的数据的时候,了解模型预测的模式,可以帮助你快速定位问题。
  • 指导工程师做特征工程。特征工程通常是提升模型准确率最有效的方法。特征工程通常涉及到到反复的操作原始数据 ( 或者之前的简单特征 ),用不同的方法来得到新的特征。有时候你完成FE的过程只用到了自己的直觉。这其实还不够,当你有上百个原始特征的时候,或者当你缺乏业务背景知识的时候,你将会需要更多的指导方向。如何创造出这样优秀的特征呢?如何找到最重要的特征的方法,并且可以发现两个特别相关的特征,当面对越来越多的特征的时候,这些方法就会很重要啦。
  • 指导数据采集的方向。对于网上下载的数据集你完全控制不了。不过很多公司和机构用数据科学来指导他们从更多方面收集数据。一般来说,收集新数据很可能花费比较高或者不是很容易,所以大家很想要知道哪些数据是值得收集的。基于模型的洞察力分析可以教你很好的理解已有的特征,这将会帮助你推断什么样子的新特征是有用的。
  • 指导人们做决策。一些决策是模型自动做出来的,虽然亚马逊不会用人工来决定展示给你网页上的商品,但是很多重要的决策是由人来做出的,而对于这些决定,模型的洞察力会比模型的预测结果更有价值。
  • 建立模型和人之间的信任。很多人在做重要决策的时候不会轻易的相信模型,除非他们验证过模型的一些基本特性,这当然是合理的。实际上,把模型的可解释性展示出来,如果可以匹配上人们对问题的理解,那么这将会建立起大家对模型的信任,即使是在那些没有数据科学知识的人群中。

模型可解释性工具SHAP

关于模型解释性,除了线性模型和决策树这种天生就有很好解释性的模型以外,sklean中有很多模型都有importance这一接口,可以查看特征的重要性。其实这已经含沙射影地体现了模型解释性的理念。只不过传统的importance的计算方法其实有很多争议,且并不总是一致。

SHAP 全称是 SHapley Additive exPlanation, 属于模型事后解释的方法,可以对复杂机器学习模型进行解释。虽然来源于博弈论,但只是以该思想作为载体。在进行局部解释时,SHAP 的核心是计算其中每个特征变量的 Shapley Value。

  • SHapley:代表对每个样本中的每一个特征变量,都计算出它的 Shapley Value。
  • Additive:代表对每一个样本而言,特征变量对应的 shapley value 是可加的。
  • exPlanation:代表对单个样本的解释,即每个特征变量是如何影响模型的预测值。

SHAP库的特性:

  • 支持任意机器学习的可解释输出与可视化展示
  • 针对集成树和神经网络类模型进行特定优化与加速
  • 能解释每一个样本的每一个特征的重要性(区分正负)
  • 能揭示不同特征间的相互作用,以及不同模型间的深入对比

SHAP的原理

在当今的金融、医疗等数据挖掘的应用领域中,模型的可解释性和精度是同等的重要。众所周知,精度较高的模型,如集成模型,深度学习模型等,内部结构复杂多变,不能直观理解。SHAP,作为一种经典的事后解释框架,可以对每一个样本中的每一个特征变量,计算出其重要性值,达到解释的效果。该值在 SHAP 中被专门称为 Shapley Value。因此 Shapley Value 是 SHAP 方法的核心所在,理解好该值背后的含义将大大有助于我们理解 SHAP 的思想。

Shapley value 最早由加州大学洛杉矶分校(UCLA)的教授 Lloyd Shapley 提出, 主要是用来解决合作博弈论中的分配均衡问题。Lloyd Shapley 是 2012 年的诺贝尔经济学奖获得者,也是博弈论领域的无冕之王。

我们已有的数据集中会包含很多特征变量,从博弈论的角度,可以把每一个特征变量当成一个玩家。用该数据集去训练模型得到的预测结果, 可以看成众多玩家合作完成一个项目的收益。Shapley value,通过考虑各个玩家做出的贡献,来公平地分配合作的收益。

Shapley value 计算

可以通过一个小例子来看如何计算 Shapley Value。

假设:合作项目 Proj=<Players, v>,Players={1,2,…n}, 每个玩家在这个项目中所做的贡献量的特征方程是 v。

定义 Proj=500 行代码,由 3 个程序员完成,这就对应 3 个玩家:1,2,3。每个玩家可以独立完成的代码:v(1)=100, v(2)=125, v(3)=50如果合作:v(1,2)=270,v(2,3)=350, v(1,3)=375, v(1,2,3)=500。

具体的合作过程有 6 种情况:

  • 玩家 1 邀请玩家 2, 玩家 2 接着邀请玩家 3;
  • 玩家 1 邀请玩家 3, 玩家 3 接着邀请玩家 2;
  • 玩家 2 邀请玩家 1, 玩家 1 接着邀请玩家 3;
  • 玩家 2 邀请玩家 3, 玩家 3 接着邀请玩家 1;
  • 玩家 3 邀请玩家 1, 玩家 1 接着邀请玩家 2;
  • 玩家 3 邀请玩家 2, 玩家 2 接着邀请玩家 1;

如果我们要合理分配,是否公平主要看边际贡献。先定义第 i 个玩家加入组织 S 的边际贡献$\delta(i)=v(S \cup {i})-v(S)$

挑选第一种情况为例:

  • 玩家1边际贡献: $v({1})=100$
  • 玩家2边际贡献: $v({1,2})-v({1})=270-100=170$
  • 玩家3边际贡献: $v({1,2,3})-v({1,2})=500-270=230$

按照上面的计算过程,依次计算剩下的 5 种情况。同时考虑到这 6 种情况是等概率出现的。完整结果如下图:

计算第 i 个玩家的 Shapley Value, 主要是由上图的边际贡献得到:

所以按照比例来分配奖金:

  • 玩家 1 分配的奖金为总奖金的3%
  • 玩家 2 分配的奖金为总奖金的3%
  • 玩家 3 分配的奖金为总奖金的3%

SHAP原理

当我们进行模型的SHAP事后解释时,我们需要明确标记。已知数据集(设有M个特征变量,n个样本),原始模型f,以及原始模型f在数据集上的所有预测值。g是SHAP中用来解释f的模型。

先用f对数据集进行预测,得到模型预测值的平均值$\phi_{0}$。单个样本表示为$x=(x_1,x_2…x_M)$,$f(x)$为在原始模型下的预测值。 $g(x)$是事后解释模型的预测值,满足$g(x)=\phi_{0}+\sum_{i=1}^{M} \phi_{i}x_{i}=f(x)$。其中$\phi_{i}$代表第i个特征变量的Shapley Value,是SHAP中的核心要计算的值,需要满足唯一性。同时上述模型g需要满足如下的性质:

  • 性质1:局部保真性 (local accuracy)。即两个模型得到的预测值相等。当输入单个样本$x$到模型g中时,得到的预测值$g(x)=\phi_{0}+\sum_{i=1}^{M}\phi_{i}x_{i}^{’}$与原始模型得到的预测值$f(x)$相等。
  • 性质2:缺失性(missingness)。如果在单个样本中存在缺失值,即某一特征变量下没有取值,对模型g没有影响,其Shapley Value为0。
  • 性质3:连续性(consistency)。当复杂模型f从随机森林变为XGBoost,如果一个特征变量对模型预测值的贡献增多,其Shapley value也会随之增加。

在上述3个限制条件下,可以理论证明求出唯一的$\phi_{i}$,即对应的模型g也是独一无二的。具体证明可参考 Shapley’s paper (1953).。

$\phi_{i}(f,x)=\sum_{S\subseteq \lbrace N \backslash i \rbrace }\frac{|S|!(M-|S|-1)!}{M!}[f_{x}(S\cup i)-f_{x}(S)]$

N={1,2…M}代表数据集中特征变量下标,1代表第一个特征变量,以此类推,i是第i个特征变量,M是特征变量的总个数。S是集合{1,2…i-1,i,…M}的子集,有$2^{M-1}$种可能。$|S|$是S中的元素的总个数。$f_{x}(S\cup i)$代表当样本中只有$S\cup i$中的特征变量值时,模型的预测值。$f_{x}(S\cup i)$代表当样本中只有$S$中的特征变量值时,模型的预测值。二者相减,可当成第i个特征变量在子集S下的边际贡献。前面的权重(kernel): $\frac{|S|!(M-|S|-1)!}{M!}$ 是根据排列组合的公式得到, 代表有相同元素个数的S存在的概率。

SHAP分类

$\phi_{i}$就是众所周知的第i个特征变量的Shapley Value。SHAP的核心是计算这个理论的Shapely Value,如果直接计算,由于特征子集的多种可能,上述计算方式的时间复杂度是指数级的。因此围绕着如何计算Shapley Value,我们根据对Shapley Value计算的两种近似方法将SHAP分为两大类。

Model-agnostic 近似

Kernel SHAP该方法借用LIME方法来估计出解释模型g中的$\phi_{i}$,属于model-agnostic的方法。Linear LIME是指使用线性模型$\omega_{0}+\sum_{i=1}^{n}\omega_{i}x_{i}$来近似原始复杂模型f。从模型的构成来看,Linear LIME拟合的回归模型与SHAP模型$\phi_{0}+\sum_{i=1}^{n}\phi_{i} x_{i}$一脉相承,满足特征的可加性。

设定好LIME中的正则化参数,加权的核函数以及损失函数进行设定。设定模型复杂度$\Omega(g)$设为0,加权核函数$\pi_{x}(z)=\frac{(M-1)}{(M choose |z|)|z|(M-|z|)}$,损失函数$L(f,g,\pi_{x}(z))=\sum_{z \in Z}\pi_{x}(z) [f(z))-g(z)]^{2}$。x是要解释的样本,z是抽取的样本点,M是x的维度,$|z|$是z的维度。

利用LIME来估计出模型g中每个变量对应的系数,也就是SHAP中的$\phi_{i}$,得到关于权重$\phi_{i}$的唯一解,在这里称为Shapley kernel。

Model-specific 近似

如果我们已知复杂模型的种类,比如树集成模型,深度学习模型等,那么可以用更快更高效的方法来计算对应每个样本中的每个特征变量的shapley value。对于不同的模型,计算Shapley Value也是不同的。TreeSHAP是专门针对树模型的SHAP方法。

树集成模型中包括很多性能优良的黑箱模型,比如随机森林、XGBoost、LightGBM和CatBoost,都属于非线性模型。Scott M. Lundberg,Su-In Lee等提出了TreeSHAP来对树模型进行局部解释。相对于model-agnostic的局部解释方法,TreeSHAP不需要抽样,而是通过对树模型中的节点来计算Shapley Value。

TreeSHAP有如下优点:

  • 计算时间减少。如果直接用Shapley Value的公式来计算,时间复杂度是指数级的,但是TreeSHAP将中计算Shapley Value的算法进行优化,时间复杂度变为线性,因此可以大大缩短运行时间。
  • 将局部解释拓展到抓取交互效应。对于每一个样本, 局部解释会对其中的每一个特征变量计算对应的值。直观来看,这种解释不能让我们直接地看到交互作用。为解决这个问题,TreeSHAP提供了计算SHAP interaction value(参考论文2)的方法来看模型内部的交互作用。
  • 基于众多局部解释来进行全局解释。对于整个数据集,可以运用Shapley Value来高效准确地获得局部解释性,即对每个样本的解释,可以帮助我们得到特征变量的全局解释。对于某一个特征变量,TreeSHAP可以计算出所有样本中对应该变量的Shapley Value, 将它们的平均值作为该特征的重要性值,从而得到全局解释。

SHAP解释

介绍完如何计算Shapley Value之后,要开始解读是Shapley Value如何影响原始模型f的预测值。假设数据集中有4个特征变量$z_1,z_2,z_3,z_4$,用原始模型f预测之后,我们以模型预测值的平均值作为其期望$E(f(z))$,即$\phi_0$。以单个样本$x=(x_1,x_2,x_3,x_4)$为例,它在原始模型中的预测值为$f(x)$, 我们计算出4个对应的Shapley Value $\phi_1,\phi_2,\phi_3,\phi_4$后开始解释。

对于整个数据集而言,$\phi_0$是固定的,是模型预测的平均值,可为正也可为负。上图解释了这个样本预测值与平均预测值之间存在差异的原因 。蓝色的箭头代表Shapley Value的值为正,意味着该特征变量对原始模型的预测值有一个正向的影响。红色的箭头代表Shapley Value的值为负,意味着该特征变量对原始模型的预测值有一个负向的影响。从图中可以看出,$\phi_4<0<\phi_1<\phi_3<\phi_2$, 所以特征变量$z_1,z_2,z_3$对$f(x)$有正向的作用,且$z_2$的作用最强。$z_4$的存在则对$f(x)$构成了负向的作用。最终在这4个特征变量的力的作用下,将该样本$x$的原始模型预测值从平均值达到了$f(x)$。

SHAP的解释模型

SHAP 可以用来解释很多模型。目前支持的模型有:

  • TreeExplainer:适用于树模型,包括决策树、随机森林和梯度提升树等。TreeExplainer 基于模型的树结构,通过对每个节点进行 Shapley value 的计算来得到每个特征的重要性。具体地,TreeExplainer 首先根据树结构将待解释样本划分为一个叶子节点,并计算该叶子节点对预测结果的贡献值。然后,从叶子节点开始向上遍历树结构,计算每个节点对预测结果的贡献差异,并根据特征的排序顺序依次累加每个特征的贡献,得到其 Shapley value。相比于其他 Explainer,TreeExplainer 的优点在于可以提供较准确的特征重要性估计值,并且考虑了特征之间的交互作用。但是,TreeExplainer 对树结构的处理方式比较复杂,需要对模型进行训练,并且可能需要调节一些参数。
  • KernelExplainer: 使用核函数来近似计算 Shapley value。具体来说,KernelExplainer 首先通过随机抽样获取一组样本,并在这些样本上拟合一个全局模型。然后,在每个样本上,根据每个特征的取值和全局模型的预测值,构建一个新的局部模型。最后,通过核函数对每个局部模型进行加权平均,得到基于全局模型的 Shapley value 近似值。相比于 ExactExplainer 和 SamplingExplainer,KernelExplainer 的优点在于可以处理任何类型的模型,并且不需要训练整个模型或采样数据集,因此计算速度较快。但是,由于核函数的选择和超参数的调节可能会影响结果,因此需要谨慎选择,并在实际应用中进行验证。
  • DeepExplainer:用于计算神经网络模型中的特征重要性。与其他 Explainer 不同的是,它可以处理深度神经网络,并考虑了每个神经元对预测结果的贡献。具体来说,DeepExplainer 会首先通过正向传播计算出模型在待解释样本上的预测值和激活值。然后,通过反向传播计算各层梯度,将梯度乘以激活值,并根据 Shapley value 对每个神经元进行权重分配,得到每个特征的重要性贡献。相比于其他 Explainer,DeepExplainer 的优点在于可以处理复杂的深度神经网络,并且能够捕捉神经元之间的交互作用。但是,由于神经网络的复杂性,DeepExplainer 的计算速度较慢,并且可能需要较长的时间来计算特征重要性。
  • GradientExplainer:使用梯度信息来近似计算 Shapley value。具体来说,GradientExplainer 首先选择一个参考点作为基准,并在该点处计算模型输出的梯度。然后,在每个样本上,通过对输入特征进行微小扰动来计算新的输入数据点,并计算模型输出的梯度差异。根据梯度的加权平均值,可以得到每个特征的 Shapley value 近似值。相比于 ExactExplainer 和 SamplingExplainer,GradientExplainer 适用于任何类型的模型,并且不需要训练整个模型或采样数据集,因此计算速度较快。但是,由于梯度计算可能会受到噪声和抖动的影响,因此可能需要调节一些参数,并在实际应用中进行验证。
  • LinearExplainer:适用于线性模型,并使用线性代数方法计算 Shapley value。具体来说,LinearExplainer 首先通过拟合一个线性模型来计算每个特征对预测结果的贡献值。然后,根据特征的排序顺序依次累加每个特征的贡献,得到其 Shapley value。相比于其他 Explainer,LinearExplainer 的优点在于可以提供精确的特征重要性估计值,并且不需要采样或近似计算。但是,它只适用于线性模型,并且可能无法捕捉非线性特征之间的交互作用。
  • PermutationExplainer:排列方法(permutation)来计算每个特征对模型预测的影响。PermutationExplainer 会先计算出对某个样本的原始预测值,然后随机地打乱该样本中某个特征的取值,并重新计算预测值。通过比较打乱前后的预测值差异,可以得到该特征对预测结果的影响。重复这个过程多次,可以得到该特征的平均影响,即特征重要性。相比于其他 Explainer,PermutationExplainer 的优点在于计算效率高,适用于大规模数据集和复杂模型,而且不需要对模型进行修改或训练。但是,它也有一些局限性,如可能会忽略特征之间的交互作用,以及只能计算某个特定的预测函数下的特征重要性。
  • PartitionExplainer:用于transformer NLP 任务,它的思想: 通过层次特征, 递归地计算Shapley值,这个层次特征定义了特征联盟(feature coalitions),以此从博弈论中得到Owen值。
  • SamplingExplainer:采样方法来近似计算 Shapley value,以提高计算效率。具体来说,SamplingExplainer 会在数据集中进行随机采样,并计算从该样本到整个数据集的贡献差异。然后,通过乘以采样比例来得到整个数据集的贡献值,并根据特征的排序顺序依次累加每个特征的贡献,得到其 Shapley value。相比于 ExactExplainer,SamplingExplainer 的计算速度更快,适用于中等规模的数据集和复杂模型。但是,由于采样导致的误差,它的精度可能不如 ExactExplainer。
  • AdditiveExplainer:基于加性模型的假设,将整个模型分解为每个特征的局部线性模型,并根据 Shapley value 对每个特征进行权重分配。AdditiveExplainer 首先通过拟合一个零模型(即不考虑任何特征的模型)来确定基准预测值。然后,在每个样本上,根据每个特征的取值和基准预测值拟合一个局部线性回归模型。最后,根据 Shapley value 对每个特征进行权重分配,得到特征的重要性分数。相比于其他 Explainer,AdditiveExplainer 的优点在于可以处理复杂的非线性模型,并可以捕捉特征之间的交互作用。但是,它的计算复杂度较高,适用于小规模数据集和简单模型。
  • ExactExplainer:使用精确计算方法来计算 Shapley value,而不是近似或采样方法。具体来说,ExactExplainer 会将所有可能的特征子集拆分为包含该特征和不包含该特征两部分,并计算两部分对预测结果的贡献差异。然后,根据特征的排序顺序依次累加每个特征的贡献,得到其 Shapley value。相比于其他 Explainer,ExactExplainer 的优点在于可以提供最准确的特征重要性估计值。但是,它的计算复杂度非常高,适用于小规模数据集和简单模型。

其他模型:

  • explainers.other.Coefficient: 这个函数用于解释线性模型的系数。给定一个线性模型,它将返回每个特征的系数和截距对应的SHAP值。这是一个基于训练数据的全局方法,可以用于理解线性模型预测的原因。
  • explainers.other.Random: 这个函数使用一种随机采样的方法来估计任何黑盒模型的SHAP值。该方法适用于任何类型的模型,并且不需要训练过程中的任何信息。该方法会进行多次的模型预测和采样,然后通过计算样本的平均预测结果与真实结果之间的差异来计算SHAP值。与其他方法相比,速度更快但精度较低。
  • explainers.other.LimeTabular: LIME(Local Interpretable Model-Agnostic Explanations)是一种局部解释方法,旨在解释单个样本的预测。LimeTabular 是 LIME 的一种变体,专门用于处理表格数据。该方法通过在样本周围生成许多新的样本并拟合一个局部线性模型来解释样本的预测。SHAP 值是从拟合的局部模型中得出的。
  • explainers.other.Maple: 这个函数将 SHAP 值视为概率分布,并使用贝叶斯推断来计算 SHAP 值的后验分布。通过使用先前的知识或假设,可以通过 Maple 来构建解释,如果我们有关于模型参数本身的知识,这种方法可能很有用。
  • explainers.other.TreeMaple: 这个函数是基于决策树的 Maple 方法。与常规 Maples 不同,TreeMaple 可以使用决策树结构优化 SHAP 值的计算。TreeMaple 可以计算单个样本的 SHAP 值,也可以计算整个数据集的 SHAP 值。
  • explainers.other.TreeGain: 这个函数是基于决策树的重要性评估方法。与 SHAP 值相比,TreeGain 更快,但提供的信息更少。该方法通过计算决策树中每个节点的增益来确定每个特征的重要性。这些增益可以看作是特征对模型的影响,而没有考虑到其他特征的相互作用。

SHAP的可视化输出

SHAP的使用非常的简单,重要的是各种图表的输出。简单的使用如下:

import shap
shap.initjs() #在notebook显示交互操作时需要

explainer = shap.TreeExplainer(lgb_model) #传入训练好的模型
shap_values = explainer.shap_values(valid_X) # 拿验证数据集进行呈现。

由于各种模型支持的图表有些许不一样,这里使用LightGBM的回归模型来讲解。

shap.summary_plot()

shap.summary_plot() 是 SHAP 库中的一个函数,可以用来可视化模型所有特征对于预测的贡献,并帮助我们识别哪些特征是最重要的。shap.summary_plot() 将会生成一个横向条形图或散点图,显示每个特征对于预测的贡献度。每个特征都被赋予一个颜色和长度,以反映其重要性,同时还显示了减号(-)或加号(+),表示该特征是如何影响模型输出的。如果特征值越高则输出越高,则该特征显示为加号;否则,该特征显示为减号。条形图或散点图按重要性从高到低排序,因此可以很容易地识别哪些特征最相关。

shap.summary_plot(shap_values, features=None, feature_names=None, max_display=None, plot_type='dot')

参数:

  • shap_values: 一个数组,其中包含了样本的 Shapley 值,大小为 [n_samples, n_features]。
  • features: 一个数组,其中包含了样本的特征矩阵。这需要与 shap_values 中的样本数量一致。
  • feature_names: 特征名称列表,长度应该和 features 的列数相同。
  • max_display: 可选参数,用于指定要显示的最多特征数量。默认情况下,将显示所有特征。
  • plot_type: 可选参数,用于指定图形类型。可以设置为 ‘dot’ 或 ‘bar’。
shap.summary_plot(shap_values, valid_X, max_display=10, plot_type='dot')

shap.summary_plot(shap_values, valid_X, max_display=10, plot_type='bar')

summary plot是针对全部样本预测的解释,有两种图,一种是取每个特征的shap values的平均绝对值来获得标准条形图,这个其实就是全局重要度,另一种是通过散点简单绘制每个样本的每个特征的shap values,通过颜色可以看到特征值大小与预测影响之间的关系,同时展示其特征值分布。

两个图都可以看到supplier_code全局重要度是最高的,其次是enum_type。第二张图其实是对shap values按照特征维度聚合计算平均绝对值。具体计算逻辑为:

feature_importance = pd.DataFrame()
feature_importance['feature'] = valid_X.columns
feature_importance['importance'] = np.abs(shap_values).mean(0)
feature_importance.sort_values('importance', ascending=False)

可以看到和条形图的关系一模一样,所以获取到shap_values后,直接对shap_values按照特征维度聚合计算平均绝对值,就可以得到summary_plot的结果。

shap.dependence_plot()

shap.dependence_plot() 是 SHAP 库中的一个函数,可以用来可视化单个特征对于预测的影响,并显示该特征的值如何与其他相关特征一起影响预测结果。这有助于我们更好地理解模型如何做出决策,并找到输入特征与输出之间的复杂非线性关系。

shap.dependence_plot(feature, shap_values, features=None, feature_names=None, interaction_index=None, display_features=None, color='#1E88E5')

参数:

  • feature: 要查看的特征名称或索引。
  • shap_values: 一个数组,其中包含了样本的 Shapley 值,大小为 [n_samples, n_features]。
  • features: 一个数组,其中包含了样本的特征矩阵。这需要与shap_values 中的样本数量一致。
  • feature_names: 特征名称列表,长度应该和features 的列数相同。
  • interaction_index: 可选参数,用于指定展示交互作用的特征。
  • display_features: 可选参数,用于指定要显示在 x 轴上的特征名称列表。默认情况下,将使用feature_names。
  • color: 可选参数,用于指定散点图的颜色。

shap.dependence_plot() 将会生成一个散点图,其中横轴表示选择的特征,纵轴表示该特征对于预测的贡献度。每个点代表一个数据点,点的颜色和位置取决于该数据点的特征值和 Shapley 值。这样就可以很容易地识别出该特征值的变化如何影响模型输出。通过设置 interaction_index 参数,您可以查看特定特征与另一个特征之间的交互作用。如果存在交互作用,则将绘制一条最佳拟合直线,以显示两个特征之间的关系。

首先先看某个特征是如何影响到模型预测结果的,这里以”enum_type”为例子,运行下面代码:

shap.dependence_plot("enum_type", shap_values, valid_X, interaction_index=None)

可以看到100左右的分值的预测结果都非常的高。接下来看下交叉特征:

shap.dependence_plot('main_code', shap_values, valid_X, interaction_index='enum_type')

shap.dependence_plot('enum_type', shap_values, valid_X, interaction_index='main_code')

以上2种写法显示了横坐标和纵坐标的差异。

shap.force_plot()

shap.force_plot() 是 SHAP 库中的一个函数,可以可视化 Shapley 值,展示单个数据点基于其所有特征的 SHAP 贡献。这有助于我们更好地理解模型如何做出预测,并且可以帮助我们在进行模型选择或优化时识别哪些特征是最重要的。shap.force_plot() 将会生成一个力导图,它显示每个特征对于当前数据点的贡献。力导图两侧分别显示了当前数据点的 SHAP 值,以及全局基线(即所有特征值取中点的情况下的预测结果)的值。由于每种特征都被赋予了一个颜色和长度,因此可以方便地查看哪些特征对模型的预测影响最大。另外,通过调整样本和特征,您可以查看模型对于不同输入的响应方式。

shap.force_plot(base_value, shap_values, features)

参数:

  • base_value: 该参数表示整体的平均预测输出值。这个值是同样的对于所有数据点。如果您使用的是分类器,则 shap_values 也将是分类器的输出概率。
  • shap_values: 一个数组,其中包含了样本的 Shapley 值,大小为 [n_samples, n_features]。
  • features: 一个数组,其中包含了样本的特征矩阵。这需要与shap_values 中的样本数量一致。

单个预测的解释可视化

# 如果不想用JS,传入matplotlib=True
shap.force_plot(explainer.expected_value, shap_values[14], valid_X.iloc[0, :], matplotlib=True)

尝试分析此图:

  • 模型输出值:19
  • 基值:模型输出与训练数据的平均值(expected_value)
  • 绘图箭头下方数字是此实例的特征值。如estimate_kilo =214.1,lost_amount=44
  • 将预测推高的特征用红色表示,将预测推低的特征用蓝色表示
  • 箭头越长,特征对输出的影响越大。通过 x 轴上刻度值可以看到影响的减少或增加量。

多个预测的解释可视化

shap.force_plot(explainer.expected_value, shap_values, valid_X)

如果对多个样本进行解释,将上述形式旋转90度然后水平并排放置,得到力图的变体,我们可以看到整个数据集的 explanations 。

通过上图中上方和左方选项卡,可以任意选择单个变量的多个样本对模型输出结果的影响。

shap.decision_plot()

shap.decision_plot() 是 SHAP 库中的一个函数,可以用来可视化决策树模型在单个样本上的预测过程,并计算每个特征对于该预测的贡献。这有助于我们更好地理解模型如何做出预测,并帮助我们在进行模型选择或优化时识别哪些特征是最重要的。

shap.decision_plot(expected_value, shap_values, features=None, feature_names=None, feature_display_range=None, highlight=None, show=True)

参数:

  • expected_value: 该参数表示整体的平均预测输出值。这个值是同样的对于所有数据点。
  • shap_values: 一个数组,其中包含了样本的 Shapley 值,大小为 [n_samples, n_features]。
  • features: 一个数组,其中包含了样本的特征矩阵。这需要与shap_values 中的样本数量一致。
  • feature_names: 特征名称列表,长度应该和features 的列数相同。
  • feature_display_range: 可选参数,用于指定每个特征在图形中所占的坐标轴范围。
  • highlight: 可选参数,用于指定要突出显示的特征。
  • show: 可选参数,用于指定是否在调用decision_plot() 后立即显示图形。

SHAP 决策图显示复杂模型如何得出其预测(即模型如何做出决策)。决策图是 SHAP value 的文字表示,使其易于解读。决策图显示的信息与力图基本相同,都可以有效地解释上述模型的预测。而且很容易识别出主要影响的大小和方向。决策图比力图更清晰和直观,尤其是要分析的特征比较多的时候。在力图中,当预测变量的数量较多时,信息可能看起来非常紧凑。

shap.decision_plot(explainer.expected_value, shap_values[14], valid_X)

决策图中间灰色垂直直线标记了模型的基础值,彩色线是预测,表示每个特征是否将输出值移动到高于或低于平均预测的值。特征值在预测线旁边以供参考。从图的底部开始,预测线显示 SHAP value 如何从基础值累积到图顶部的模型最终分数。

shap.decision_plot(explainer.expected_value, shap_values[:10], valid_X,highlight=0)

显示了TOP 10条记录的决策图,并高亮显示了第一个。

shap.plots.waterfall()

shap.plots.waterfall() 是 SHAP 库中的一个函数,可以用来可视化单个样本的预测结果以及每个特征对于该预测结果的影响。这有助于我们更好地理解模型如何做出决策,并帮助我们识别哪些特征是最重要的。

shap.plots.waterfall(shap_values, max_display=None, show=True)

参数

  • shap_values: 一个数组,其中包含了样本的 Shapley 值,大小为 [n_features]。
  • max_display: 可选参数,用于指定要显示的最多特征数量。默认情况下,将显示所有特征。
  • show: 可选参数,用于指定是否在调用 waterfall() 后立即显示图形。

shap.plots.waterfall() 将会生成一个瀑布图,用于显示单个样本的预测结果以及每个特征对于该预测结果的影响。顶部的条形表示总体预测结果,而下方的每个条形则表示每个特征对于总体预测结果的贡献。瀑布图按照贡献度从高到低排序,因此可以很容易地看到哪些特征是最相关的。

每个条形都被赋予一个颜色和长度,以反映其贡献度,同时还显示了减号(-)或加号(+),表示该特征是如何影响模型输出的。如果特征值越高则输出越高,则该特征显示为加号;否则,该特征显示为减号。

但直接使用此方法shap.plots.waterfall(shap_values)可能会保如下错误:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [129], in <cell line: 1>()
----> 1 shap.plots.waterfall(shap_values)

File ~/anaconda3/lib/python3.9/site-packages/shap/plots/_waterfall.py:45, in waterfall(shap_values, max_display, show)
     42 if show is False:
     43     plt.ioff()
---> 45 base_values = shap_values.base_values
     46 features = shap_values.display_data if shap_values.display_data is not None else shap_values.data
     47 feature_names = shap_values.feature_names

AttributeError: 'numpy.ndarray' object has no attribute 'base_values'

解决方法是使用此方法替代:

shap.plots._waterfall.waterfall_legacy(explainer.expected_value,shap_values[14],feature_names=valid_X.columns)

参考链接:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注