随着机器学习特别是深度学习的应用越来越广泛,其“黑箱”特性(即模型内部复杂的决策机制难以理解)带来了信任、伦理、法律和安全等方面的挑战,因此可解释性变得至关重要,本篇博客对其做了相关讲解并结合实战重点介绍了SHAP这种模型无关的解释方法,希望能对大家有所帮助。
目录
1. 背景介绍
传统的机器学习方法往往模型越复杂,预测性能越好,但是随之的可解释性也越差,如下图所示。除了一些简单的线性回归、逻辑回归和决策树等模型本身就有一定的解释性外(自解释性),像随机森林、梯度提升树这样的集成学习以及SVM和神经网络这种复杂点的算法模型解释性就较差。而可解释机器学习就是要通过对自解释方法和事后解释方法实现对模型决策的解释说明。
2. SHAP方法
在事后解释方法中又分为模型无关和特定模型方法,其中SHAP(SHapley Additive exPlanations)是一种重要的模型无关方法。它的基础思想是计算特征对模型输出的边际贡献,再从全局和局部两个层面对“黑盒模型”进行解释。它将所有特征都视为“贡献者”,使用博弈论里的Shapley值计算边际贡献,构建一个可加的解释性模型。
Shapley值的计算公式如下:
3. SHAP实战
我们可以结合python代码以阿里云天池的蒸汽数据集(工业蒸汽量预测_学习赛_天池大赛-阿里云天池的赛制)为例来具体理解下这种方法,首先在命令行安装SHAP,然后进行以下操作:
pip install shap
or
conda install -c conda-forge shap
(1)读入数据
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
df_train=pd.read_csv(r"D:\zhengqi_train.txt",sep='\t')
df_test=pd.read_csv(r"D:\zhengqi_test.txt",sep='\t')
df_train.head()
df_test.head()
(2)划分数据集并建模
中间省略了数据预处理、特征工程、建模、参数调优等一系列操作
from sklearn.model_selection import train_test_split
# 划分训练和验证集合
df_train_value=df_train.drop("target",axis=1)
df_train_target=df_train["target"]
df_train_value, df_val_value, df_train_target, df_val_target=train_test_split(df_train_value, df_train_target, test_size=0.25,random_state=1)
#重置索引
df_train_value=df_train_value.reset_index(drop=True)
df_val_value=df_val_value.reset_index(drop=True)
df_train_target=df_train_target.reset_index(drop=True)
df_val_target=df_val_target.reset_index(drop=True)
#转为矩阵
df_train_value=np.array(df_train_value)
df_val_value=np.array(df_val_value)
df_train_target=np.array(df_train_target)
df_val_target=np.array(df_val_target)
#建模
from sklearn.metrics import mean_squared_error
import xgboost as xgb
model_xgb=xgb.XGBRegressor(max_depth=5, learning_rate=0.1, n_estimators=160, silent=True, objective='reg:linear')
model_xgb.fit(df_train_value,df_train_target)
predict_xgb=model_xgb.predict(df_val_value)
mean_squared_error(df_val_target,predict_xgb) #mse为0.104
(3)使用SHAP方法进行解释
现在我们得到了一个XGBRegressor模型,可以开始使用SHAP对这个模型进行解释
① 全局特征重要性分析
import shap
import matplotlib.pyplot as plt
# 创建 SHAP 解释器
explainer = shap.Explainer(model_xgb, df_train_value)
# 计算 SHAP 值
shap_values = explainer(df_val_value)
# 全局特征重要性分析
shap.summary_plot(shap_values, df_val_value)
plt.show()
运行结果:
对这幅图的解读
- 每一个点表示一个样本。
- 点的横坐标是该样本对应这个特征的 SHAP 值(该特征对预测结果的影响,>0代表正向影响,<0是负向影响,绝对值越大影响越大)。
- 点的颜色是该样本在这个特征上的具体取值(特征值),从小到大用蓝色到红色的渐变表示。
- 从上到下的特征按照对模型的重要性排序,越靠上的特征,对预测结果的平均贡献越大(默认展示排名前20的特征)
- 这帮助我们观察每个特征的全局重要性(特征的 SHAP 值分布宽度和位置)和特征值的高低如何影响预测值(通过颜色和位置的关系)。
② 单个样本的局部可解释性
# 单个样本的局部可解释性分析(例如,针对第一个样本)
shap.waterfall_plot(shap_values[0])
plt.show()
运行结果:
对这幅图的解读:
- 这是针对第一个样本的局部可解释性图
- 初始预测值(
E[f(X)] = 0.265
)是模型在不考虑特征影响时的平均预测值 - 特征通过 SHAP 值叠加对预测值产生正向或负向影响,从上到下影响逐渐减小
- 纵轴的-0.203=Feature 1表示特征1的取值是-0.203,下面的-0.025,-0.07等类似
- 终点
f(x)=
-0.064表示
样本的最终预测值
③ 每个特征对预测值的贡献
# 强制图(force plot)展示每个特征对预测值的贡献
shap.force_plot(explainer.expected_value, shap_values[0].values, df_val_value[0], matplotlib=True)
plt.show()
运行结果:
对这幅图的解读: 从 Base Value 出发,将所有特征 SHAP 值叠加,得到最终预测值
④ SHAP依赖图
# 交互特征可视化
shap.dependence_plot(0, shap_values.values, df_val_value, show=False)
plt.show()
运行结果:
对这幅图的解读:
- 展示某一特征的 SHAP 值与其原始值的关系,同时体现与其他特征的交互作用
- 横轴是Feature 0的取值,纵轴是Feature 0对模型预测的贡献(SHAP值),颜色表示另一个特征(Feature 8)的取值,用于显示 Feature 0 与 Feature 8 的交互作用。
- Feature 0 的 SHAP 值随其取值变化呈线性增长,表明 Feature 0 的值越大,对模型预测的正向贡献越大。
- 当 Feature 0 取值较小时(负值区间),其 SHAP 值为负,对模型起削弱作用。
- 从颜色(Feature 8)分布看,随着 Feature 8 的值变大(从蓝色到红色),SHAP 值整体呈现明显上升。
- 这表明 Feature 0 和 Feature 8 存在一定的交互关系——Feature 8 的取值对 Feature 0 的 SHAP 值有放大作用,在高值区间更加明显。
参考文献:
Welcome to the SHAP documentation — SHAP latest documentation