所有文章 > AI驱动 > 不止 SHAP 力图:LIME 实现任意黑盒模型的单样本解释

不止 SHAP 力图:LIME 实现任意黑盒模型的单样本解释

背景

LIME是一个用于解释机器学习模型预测结果的技术,它的主要目的是帮助人们理解黑箱模型(如深度学习模型随机森林等)的预测决策,针对于单个预测样本的特征贡献度解释

LIME原理

LIME 的核心思想是在模型的局部(即一个特定的数据点附近)建立一个简单的、可解释的模型(通常是线性模型),这个简单模型可以近似原始复杂模型在该数据点附近的行为,具体步骤如下:

  • 扰动数据点:LIME 首先对需要解释的输入数据点进行扰动,生成一组邻近的数据点。这些邻近的数据点和原始模型的预测结果一起构成了一个新的数据集
  • 训练局部解释模型:LIME 使用这个新数据集来训练一个简单的、可解释的模型(如线性回归),这个简单模型被设计成在邻近区域内近似原始模型的预测
  • 解释预测:通过观察这个局部解释模型的权重,LIME 可以提供关于原始复杂模型为什么在特定数据点上做出某个预测的解释

LIME 的特点

  • 模型无关性:LIME 不依赖于具体的机器学习模型,它可以用于任何类型的模型(即模型无关)
  • 局部解释:LIME 提供的是局部解释,即针对特定数据点的解释,而不是整个模型的全局解释
  • 可解释性:通过使用简单的模型(如线性模型),LIME 提供的解释更容易被理解

总的来说,这种方法的优点在于它可以为任何黑箱模型(如神经网络随机森林等)提供可解释性,使我们能够理解单个预测的背后原因,LIME 解释的是模型在某个特定样本周围的局部行为,而不是整体行为,因此非常适合用来解释单个样本的预测结果

代码实现

数据读入模型训练

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier

# 读取数据集
df = pd.read_csv('Dataset.csv')

# 划分特征和目标变量
X = df.drop(['target'], axis=1)
y = df['target']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=df['target'])

# 创建随机森林分类器实例
rf_classifier = RandomForestClassifier(
n_estimators=100,
criterion='gini',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
random_state=42,
max_leaf_nodes=None,
min_impurity_decrease=0.0
)

# 训练模型
rf_classifier.fit(X_train, y_train)

代码加载了UCI上的Heart Disease数据集,划分了训练集和测试集,并使用随机森林分类器对训练数据进行训练,以构建一个预测心脏病患病风险的分类模型,该模型的目的是通过分析患者的特征来判断其是否患有心脏病,从而为早期诊断和治疗提供支持

模型单样本解释

from lime.lime_tabular import LimeTabularExplainer
import warnings
warnings.filterwarnings("ignore", message=".*does not have valid feature names.*")

# 创建 LIME 解释器对象
explainer = LimeTabularExplainer(
training_data=X_train.values,
feature_names=X.columns,
class_names=['False', 'True'], # 根据你的具体分类任务调整类名
mode='classification'
)

# 选择一个要解释的测试集样本(例如,选择第一个样本)
sample_index = 0
sample = X_test.iloc[sample_index].values.reshape(1, -1)

# 生成解释
exp = explainer.explain_instance(
data_row=sample.flatten(),
predict_fn=rf_classifier.predict_proba
)


# 显示解释结果
exp.show_in_notebook(show_table=True)

使用 LIME 解释了随机森林分类器对 UCI Heart Disease 数据集中第一个测试样本的预测结果,在解释中,类别设置为 False 表示未患病,True 表示患病,以便更直观地理解模型的决策过程

结果解读

根据 LIME 的解释结果,模型预测该样本未患病的概率为 96%,患病的概率为 4%。以下是对特征贡献度的详细解释:

对“未患病” (False) 预测结果有正向贡献的特征:

  • cp:值为 2.0,低于 3.0,强烈支持“未患病”的预测
  • ca:值为 0,表明没有阻塞的主要血管,这也是“未患病”的强支持因素
  • thal:值为 0.0,支持“未患病”
  • slope:值为 1.0,属于较平缓的斜率,支持“未患病”
  • oldpeak:值为 0.0,表示没有显著的 ST 段抑制,支持“未患病”
  • chol:值为 157.0,处于正常范围,也支持“未患病”

其余对“未患病” (False) 预测结果有正向贡献的特征类似解读,这里不一一给出

对“患病” (True) 预测结果有正向贡献的特征:

  • sex:值为 1.0,表示男性,男性通常患心脏病的风险更高,因此略微倾向于“患病”

总体来说,模型认为该样本中的大多数特征指向“未患病”,这些特征的组合使得模型更倾向于预测该样本为“未患病”,只有性别这个特征对“患病”有一定的贡献,但不足以改变整体的预测结果

同样本shap力图解释

import shap
# 构建 shap解释器
explainer = shap.TreeExplainer(rf_classifier)
# 计算测试集的shap值
shap_values = explainer.shap_values(X_test)

# 绘制单个样本的SHAP解释(Force Plot)
sample_index = 0 # 选择一个样本索引进行解释
shap.force_plot(explainer.expected_value[0], shap_values[:, :, 0][sample_index], X_test.iloc[sample_index], matplotlib=True)
shap.force_plot(explainer.expected_value[1], shap_values[:, :, 1][sample_index], X_test.iloc[sample_index], matplotlib=True)

这里对同一个样本(测试集中的第一个数据)生成了 SHAP 力图解释,读者可以自行对比 SHAP 和 LIME 两种解释方法的结果差异

总结

在心脏病预测的案例中,LIME 被用于解释模型为什么认为某个患者未患有心脏病的风险较高,通过分析关键特征对预测结果的影响,LIME 提供了一个清晰的解释,使医疗专业人员能够理解模型的决策过程,这种能力使得 LIME 在许多需要解释性和透明性的应用场景中非常有用,例如:

  • 信用评分:解释为什么某个申请人的信用得分较低,从而帮助金融机构做出更加透明的信贷决策
  • 医疗诊断:解释为什么模型认为某个患者患有特定疾病的风险较高,以支持医生的诊断和治疗方案
  • 图像分类:解释为什么模型将某张图片分类为特定类别,有助于提高模型在计算机视觉任务中的信任度

当然不局限于这些领域,通过简化复杂模型的局部行为,LIME 使得用户能够更好地信任和理解机器学习模型的预测结果,在需要平衡准确性和可解释性的领域尤为重要

文章转自微信公众号@Python机器学习AI