背景
LIME是一种模型无关的解释工具,用于解释机器学习模型的预测结果。其核心思想是:通过在输入数据的局部邻域中生成随机样本,并用一个简单的可解释模型(如线性模型)拟合这些样本的预测结果,从而得出特定样本的特征贡献。LIME不依赖于具体的模型类型,可以用于任何黑盒模型(如深度学习、XGBoost等),帮助理解模型对单个实例的预测原因,特别适用于复杂的非线性模型或不可解释的场景,但是它存在一个不可避免的缺点,接下来在代码实现里面进行展示
代码实现
模型构建
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['axes.unicode_minus'] = False
from sklearn.model_selection import train_test_split
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
df = pd.read_excel('2024-12-27公众号Python机器学习AI.xlsx')
# 划分特征和目标变量
X = df.drop(['y'], axis=1)
y = df['y']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
random_state=42, stratify=df['y'])
from xgboost import XGBClassifier
from sklearn.model_selection import GridSearchCV, StratifiedKFold
from sklearn.metrics import accuracy_score
# 定义 XGBoost 二分类模型
model_xgb = XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=8)
# 定义参数网格
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [3, 5, 7],
'learning_rate': [0.01, 0.1, 0.2],
'subsample': [0.8, 1.0],
'colsample_bytree': [0.8, 1.0]
}
# 定义 K 折交叉验证 (Stratified K-Fold)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=8)
# 使用网格搜索寻找最佳参数
grid_search = GridSearchCV(estimator=model_xgb, param_grid=param_grid, scoring='accuracy',
cv=kfold, verbose=1, n_jobs=-1)
# 拟合模型
grid_search.fit(X_train, y_train)
# 使用最优参数训练模型
xgboost = grid_search.best_estimator_
使用XGBoost二分类模型完成以下步骤:首先,将数据划分为训练集和测试集;然后定义 XGBoost模型及其超参数搜索网格,并通过分层5折交叉验证结合网格搜索来优化模型的超参数;最后,基于最优超参数重新训练模型,为后续预测和评估做好准备
LIME解释
from lime.lime_tabular import LimeTabularExplainer
# 初始化 LIME 解释器
explainer = LimeTabularExplainer(
training_data=np.array(X_train), # 训练数据
feature_names=X.columns.tolist(), # 特征名称
class_names=['survival', 'death'], # 分类标签(根据实际情况修改)
mode='classification' # 模式为分类
)
初始化一个 LIME(局部可解释模型)解释器,用于解释分类模型的单个预测结果,其中参数分别为:training_data(训练数据,作为生成邻域样本的基础),feature_names(特征名称,用于显示特征信息),class_names(分类标签的名称,用于显示预测类别),以及mode(指定为分类模式)
果是回归模型,初始化 LIME 解释器时需要将mode参数修改为 'regression',并且不需要提供 class_names参数,因为回归任务没有离散的类别标签,只有连续的预测值
# 从测试集中选取一个样本
test_instance = X_test.iloc[0]
test_instance_array = test_instance.values.reshape(1, -1)
从测试集中选取第一行样本,并将其转化为适合模型预测的二维数组格式(1 行,n 个特征)
# 生成样本解释
exp = explainer.explain_instance(
data_row=test_instance, # 测试样本数据
predict_fn=xgboost.predict_proba # 使用模型的预测概率方法
)
使用LIME解释器对选定的测试样本进行解释,通过调用模型的预测概率方法(predict_proba),分析每个特征对该样本预测结果的贡献
# 显示解释
exp.show_in_notebook(show_table=True) # 在 Notebook 中显示解释表
exp.save_to_file("lime_explanation.html") # 保存解释到 HTML 文件
展示LIME对某个样本的解释,分为三部分,其中包括模型的预测概率(左上角),特征对分类结果(生存和死亡)的贡献(中间的条形图),以及该样本对应的特征取值(右侧表格)
左上角显示模型对该样本的预测概率,其中 "survival" 的概率为 0.93,"death" 的概率为 0.07;中间的条形图显示各特征对预测结果的贡献,其中蓝色表示推动预测为 "survival",橙色表示推动预测为 "death",条形长度表示贡献大小,例如 X_3 <= 3.00 强烈推动预测为 "survival";右侧表格列出了样本中每个特征的实际取值,帮助理解具体特征值如何影响模型预测结果
# Extract explanation data
exp_data = exp.as_list()
# Convert to DataFrame
lime_df = pd.DataFrame(exp_data, columns=['Feature', 'Contribution'])
# Plot
lime_df = lime_df.sort_values(by='Contribution', ascending=False)
plt.barh(lime_df['Feature'], lime_df['Contribution'], color=lime_df['Contribution'].apply(lambda x: 'green' if x > 0 else 'red'))
plt.xlabel("Contribution")
plt.title("Local Explanation for Class Death")
plt.show()
提取LIME对单个样本的解释数据,将每个特征对分类结果(死亡)的贡献可视化为水平条形图,其中正值(绿色)表示推动预测为 "死亡",负值(红色)表示抑制预测为 "死亡",条形的长度表示贡献大小,图中展示了各特征对死亡分类结果的局部影响
# 从测试集中选取一个样本
test_instance = X_test.iloc[0]
test_instance_array = test_instance.values.reshape(1, -1)
# 生成样本解释
exp = explainer.explain_instance(
data_row=test_instance, # 测试样本数据
predict_fn=xgboost.predict_proba # 使用模型的预测概率方法
)
# Extract explanation data
exp_data = exp.as_list()
# Convert to DataFrame
lime_df = pd.DataFrame(exp_data, columns=['Feature', 'Contribution'])
# Plot
lime_df = lime_df.sort_values(by='Contribution', ascending=False)
plt.barh(lime_df['Feature'], lime_df['Contribution'], color=lime_df['Contribution'].apply(lambda x: 'green' if x > 0 else 'red'))
plt.xlabel("Contribution")
plt.title("Local Explanation for Class Death")
plt.show()
这里针对的样本、模型和前面一模一样,但是即使针对相同的样本和模型, LIME的输出结果可能存在一定差异,这通常是由于以下原因:
- LIME在生成局部邻域数据时使用随机采样方法(如随机生成特征扰动)。这些随机性会导致局部拟合模型的结果略有不同,从而影响解释
- 每次解释时,生成的邻域样本可能不同。如果扰动样本的数量或特征分布稍有不同,解释结果可能会有差异
- LIME使用简单的线性模型拟合复杂模型的局部行为。这种近似方法依赖于随机生成的邻域数据,因此解释结果可能不完全一致
不稳定意味着很难相信解释,所以使用者可以操纵LIME解释来隐藏偏见,操纵的可能性使得更难相信LIME生成的解释,代码与数据集获取:如需获取本文的源代码和数据集,请添加作者微信联系
往期推荐
期刊配图:ALE(累积局部效应)模型解释方法解决部分依赖图PDP多重共线性问题
期刊配图:多种机器学习算法结合SHAP特征贡献在递归特征选择中的运用
复现SCI文章 SHAP 依赖图可视化以增强机器学习模型的可解释性
复现 Nature 图表——基于PCA的高维数据降维与可视化实践及其扩展
复现Nature图表——基于PCA降维与模型预测概率的分类效果可视化
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~
个人观点,仅供参考