shap TreeExplainer不支持sklearn StackingClassifier如何用force_plot
问题描述
对sklearn.ensemble._stacking.StackingClassifier模型使用Shap库的TreeExplainer开展可解释性分析,编写代码如下:
explainer = shap.TreeExplainer(clf) shap_values = explainer.shap_values(x) shap.initjs() return shap.force_plot(explainer.expected_value[1], shap_values[1], x)
运行代码时抛出报错:
Model type not yet supported by TreeExplainer: <class 'sklearn.ensemble._stacking.StackingClassifier'>
需要找到针对sklearn的StackingClassifier模型正常使用shap的force_plot功能的实现方法。
报错原因
TreeExplainer是针对树结构模型设计的专用解释器,仅原生支持单棵决策树、随机森林、GBDT、XGBoost、LightGBM这类纯树结构的单体/同质集成模型。StackingClassifier是多层异质堆叠集成结构,由第一层多个异质基学习器、第二层元分类器组合而成,不属于TreeExplainer的原生支持范围,直接传入必然触发类型不支持报错。
可行解决方案
通用兼容方案(推荐):使用KernelExplainer做模型无关解释
KernelExplainer是SHAP提供的模型无关解释器,不限制模型类型,适配所有符合sklearn预测接口的模型,实现代码如下:
import shap # 初始化JS可视化组件,仅jupyter环境需要执行 shap.initjs() # 采样100条左右的样本作为背景数据集,大幅降低计算量,不要直接传入全量数据集 background_data = shap.kmeans(x, 100) # 初始化解释器:二分类场景传入正类预测概率函数,多分类场景直接传入clf.predict_proba即可 explainer = shap.KernelExplainer( model=lambda input_data: clf.predict_proba(input_data)[:, 1], data=background_data ) # 计算待解释样本的SHAP值 shap_values = explainer.shap_values(x) # 生成force_plot,KernelExplainer的expected_value为单值,对应传入即可 force_plot_res = shap.force_plot(explainer.expected_value, shap_values, x)
- 该方案兼容性最强,哪怕StackingClassifier的基学习器包含逻辑回归、SVM等非树模型也可以正常运行
- 背景数据集采样量控制在50-200条即可平衡计算速度和解释准确率,采样量过大会导致计算耗时指数级上升
高性能方案(仅全树结构堆叠适用):拆解堆叠结构适配TreeExplainer
如果你的StackingClassifier第一层所有基学习器、第二层元分类器全部为树模型,可以手动拆解堆叠流程提升计算速度:
- 先用训练好的第一层基学习器对输入样本做预测,将各基学习器的输出概率拼接为新的特征矩阵
- 单独对第二层的元分类器(即
clf.final_estimator_)初始化TreeExplainer - 基于拼接得到的新特征矩阵计算SHAP值、绘制force_plot
- 该方案计算速度远高于KernelExplainer,但得到的SHAP值是针对堆叠层输出特征的,如果需要映射回原始输入特征,需要额外实现特征贡献传导逻辑,实现成本较高,仅适合对推理速度要求高的场景使用。
避坑提示
- 不要通过修改SHAP源码跳过模型类型校验的方式强行传入StackingClassifier,会因为模型结构不符合TreeExplainer的解析逻辑,得到完全错误的SHAP值,解释结果没有参考意义
- 多分类场景下初始化KernelExplainer时直接传入
clf.predict_proba即可,此时shap_values会按类别返回数组,调用force_plot时对应传入目标类别的expected_value和shap_value切片即可
内容的提问来源于stack exchange,提问作者Ofir
相关产品推荐
相关产品推荐

