跳转至

可解释 AI:SHAP 与 LIME


一句话说明

SHAP 和 LIME 让黑盒机器学习模型"说出"它为什么做出某个预测——告诉你哪些特征(基因/指标)对预测结果贡献最大,这在生信中对发现生物标志物至关重要。


核心知识点

为什么需要可解释性?

  • 黑盒模型(随机森林、神经网络)预测准但不知道原因
  • 生信研究需要知道"哪些基因重要"而不只是"预测结果"
  • 临床应用中需要医生理解模型判断依据
  • 监管要求(FDA 要求 AI 辅助诊断可解释)

SHAP(SHapley Additive exPlanations)

核心思想:博弈论 Shapley 值——公平分配每个特征对预测结果的"功劳"

直觉:把特征看作合作游戏的玩家,SHAP 值是每个玩家的公平报酬

预测值 = 基准值(base value) + Σ SHAP值(特征i)
SHAP 类型适用模型速度
TreeSHAP树模型(XGBoost、RF)极快
KernelSHAP任何模型
DeepSHAP神经网络中等
LinearSHAP线性模型极快

LIME(Local Interpretable Model-agnostic Explanations)

核心思想:在待解释样本附近局部扰动,拟合简单线性模型 1. 对样本特征做局部扰动 2. 用原始模型预测扰动后的结果 3. 用线性模型拟合这些扰动数据 4. 线性模型系数 = 特征重要性

SHAP vs LIME 对比

维度SHAPLIME
理论基础博弈论,有公理保证局部线性近似
一致性全局一致局部,可能不一致
速度TreeSHAP 快较慢
适用范围任何模型任何模型
首选生信推荐用 SHAP快速探索时用

实战代码

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

# ===== 1. 准备:训练一个预测 2 型糖尿病的随机森林 =====
np.random.seed(42)

# 模拟基因表达 + 临床特征数据
n_samples = 500
feature_names = [
    'gene_PPARG', 'gene_TCF7L2', 'gene_KCNJ11',  # 已知糖尿病相关基因
    'BMI', 'age', 'fasting_glucose', 'HbA1c',     # 临床指标
    'gene_FTO', 'gene_SLC30A8', 'gene_IGF2BP2'   # 更多基因
]

X, y = make_classification(
    n_samples=n_samples,
    n_features=len(feature_names),
    n_informative=6,   # 6 个真正有信息量的特征
    n_redundant=2,
    random_state=42
)

X_df = pd.DataFrame(X, columns=feature_names)
X_train, X_test, y_train, y_test = train_test_split(X_df, y, test_size=0.2, random_state=42)

# 训练随机森林
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)
print(f'模型准确率: {rf_model.score(X_test, y_test):.3f}')

# ===== 2. SHAP 分析 =====
# pip install shap
import shap

# TreeExplainer:专为树模型优化,速度极快
explainer = shap.TreeExplainer(rf_model)

# 计算测试集的 SHAP 值
# shap_values 形状: [类别数, 样本数, 特征数]
shap_values = explainer.shap_values(X_test)

# 对二分类问题,取类别1(患病)的 SHAP 值
shap_values_class1 = shap_values[1]  # [样本数, 特征数]

print(f'\nSHAP 值形状: {shap_values_class1.shape}')

# --- 全局特征重要性 ---
# 每个特征的平均绝对 SHAP 值 = 全局重要性
mean_shap = np.abs(shap_values_class1).mean(axis=0)
feature_importance_df = pd.DataFrame({
    'feature': feature_names,
    'mean_abs_shap': mean_shap
}).sort_values('mean_abs_shap', ascending=False)
print('\n全局特征重要性(SHAP):')
print(feature_importance_df.to_string(index=False))

# --- 单样本解释 ---
sample_idx = 0  # 第一个测试样本
sample_shap = shap_values_class1[sample_idx]  # 该样本每个特征的 SHAP 值
base_value = explainer.expected_value[1]       # 基准预测值(所有样本的平均预测)

print(f'\n样本 {sample_idx} 的预测解释:')
print(f'基准值 (base value): {base_value:.3f}')
for feat, shap_val in zip(feature_names, sample_shap):
    direction = '↑' if shap_val > 0 else '↓'  # 正值增加患病概率,负值降低
    print(f'  {feat}: SHAP={shap_val:+.3f} {direction}')
print(f'最终预测值: {base_value + sample_shap.sum():.3f}')

# 可视化(需要 matplotlib)
try:
    import matplotlib.pyplot as plt

    # 蜂巢图:展示所有样本所有特征的 SHAP 值分布
    shap.summary_plot(shap_values_class1, X_test, feature_names=feature_names, show=False)
    plt.tight_layout()
    plt.savefig('/tmp/shap_summary.png', dpi=100, bbox_inches='tight')
    print('\nSHAP summary plot 已保存到 /tmp/shap_summary.png')
    plt.close()
except Exception as e:
    print(f'可视化跳过: {e}')

# ===== 3. LIME 分析 =====
# pip install lime
try:
    import lime
    import lime.lime_tabular

    # 创建 LIME 解释器
    lime_explainer = lime.lime_tabular.LimeTabularExplainer(
        X_train.values,              # 训练数据(用于估计特征分布)
        feature_names=feature_names,
        class_names=['正常', '糖尿病'],
        mode='classification'
    )

    # 解释单个样本
    sample = X_test.iloc[0].values  # 取第一个测试样本

    explanation = lime_explainer.explain_instance(
        sample,
        rf_model.predict_proba,      # 模型预测函数
        num_features=5               # 展示最重要的 5 个特征
    )

    print('\nLIME 解释(前5个重要特征):')
    for feat, weight in explanation.as_list():
        print(f'  {feat}: {weight:+.4f}')
except ImportError:
    print("需要安装 lime: pip install lime")

面试常问点

Q: SHAP 和特征重要性(Feature Importance)有什么区别? A: 随机森林的默认特征重要性基于 Gini 不纯度减少,有偏差(偏爱高基数特征),且没有方向性。SHAP 更准确、有理论保证,且能告诉你每个特征增加还是降低预测值。

Q: SHAP 的 base value 是什么? A: 所有训练样本的平均预测值,相当于"如果什么特征信息都不知道"时的预测。每个样本的预测 = base value + 所有 SHAP 值的加和。

Q: 生信中 SHAP 怎么帮助发现生物标志物? A: 训练分类模型(如癌症 vs 正常),用 SHAP 找出对预测贡献最大的基因,这些基因是候选生物标志物,再做实验验证。

Q: LIME 的局限性是什么? A: ①局部线性假设不一定成立;②扰动采样方式影响结果;③不同次运行结果可能不一致(随机性)。


速查表

术语解释
SHAP 值特征对预测值贡献的公平度量
base value平均预测值(无任何特征信息时)
TreeSHAP树模型的精确快速 SHAP 实现
KernelSHAP与模型无关的 SHAP 实现(慢)
蜂巢图 beeswarmSHAP 值全局分布可视化
依赖图 dependence plot单特征 SHAP 值 vs 特征值散点图
瀑布图 waterfall单样本 SHAP 分解可视化
LIME 邻域在局部扰动样本构成的"邻域"拟合