在金融、医疗或招聘等高度监管的行业中,仅仅依靠高精度的AI模型是不够的。当模型做出关键决策(如拒绝贷款或诊断疾病)时,必须能够向用户或监管机构提供清晰、公正且可追溯的解释。这就是可解释人工智能(XAI)的核心价值。
SHAP(SHapley Additive exPlanations)是一种基于合作博弈论的解释方法,它将每个特征对预测结果的贡献公平地分配,其理论基础使其成为实现合规性解释的首选工具。
本文将以一个假想的信贷审批模型为例,演示如何使用shap库为单个拒绝决策生成合规报告。
1. 环境准备与依赖安装
我们需要安装pandas, scikit-learn 和 shap 库。
pip install pandas scikit-learn shap
2. 训练一个用于演示的信贷模型
我们首先生成一个用于信贷审批的合成数据集,并使用可靠的随机森林分类器进行训练。我们将尝试预测申请人是否会被“批准”(1)或“拒绝”(0)。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import shap
# 2.1. 创建合成数据集
np.random.seed(42)
N = 1000
data = pd.DataFrame({
'Income_k': np.random.randint(30, 150, N),
'Credit_Score': np.random.randint(500, 850, N),
'Debt_Ratio': np.random.rand(N) * 0.5 + 0.1, # 10% to 60%
'Loan_Amount_k': np.random.randint(5, 50, N)
})
# 创建目标变量:基于低收入、低信用分和高负债率拒绝贷款
target = (
(data['Income_k'] < 50) |
(data['Credit_Score'] < 600) |
(data['Debt_Ratio'] > 0.4)
)
# 目标: 1为批准,0为拒绝
data['Approved'] = (~target).astype(int)
X = data.drop('Approved', axis=1)
Y = data['Approved']
# 2.2. 训练模型
model = RandomForestClassifier(n_estimators=100, random_state=42, max_depth=5)
model.fit(X, Y)
print(f"模型精度: {model.score(X, Y):.4f}")
3. 使用SHAP进行局部解释
对于像随机森林这样的树模型,SHAP提供了高效的TreeExplainer。我们的目标是选择一个被模型拒绝的申请人(即预测概率接近0),并解释拒绝的原因。
# 3.1. 找到一个被拒绝的个体实例
# 找出预测概率最低(最可能被拒绝)的实例
probabilities = model.predict_proba(X)[:, 1] # 批准的概率
rejected_index = np.argmin(probabilities)
rejected_instance = X.iloc[rejected_index]
# 打印实例信息和预测结果
print("\n--- 待解释的被拒绝实例 ---")
print(rejected_instance)
print(f"模型预测批准概率: {probabilities[rejected_index]:.4f}")
# 3.2. 初始化Explainer并计算SHAP值
explainer = shap.TreeExplainer(model)
# SHAP值是针对批准(目标类别1)计算的
shap_values = explainer.shap_values(rejected_instance)
# 对于分类任务,shap_values返回一个列表 [SHAP_for_class_0, SHAP_for_class_1]
# 我们关注的是对“批准” (class 1) 的贡献
shap_values_class_1 = shap_values[1]
# SHAP基线值 (base value) 是训练集输出的平均预期值 (E[f(x)])
base_value = explainer.expected_value[1]
print("\n--- SHAP解释结果(对批准概率的贡献)---")
print(f"基线批准概率 (Base Value): {base_value:.4f}")
print(f"所有特征贡献和(SHAP Values Sum): {np.sum(shap_values_class_1):.4f}")
print(f"最终预测值 (Base Value + Sum of SHAP): {base_value + np.sum(shap_values_class_1):.4f}")
4. 转换SHAP结果为合规报告
合规性解释报告不能直接呈现原始SHAP值,而必须转换成人类可读的格式。我们关注的是负面贡献(即导致拒绝的因素)的特征,并按绝对值排序,以确定“最重要的拒绝原因”。
关键概念:
- 基线值 (Base Value): 训练集上模型输出的平均批准概率。
- SHAP值: 特征的贡献。负值表示该特征将预测结果推向拒绝(0),正值推向批准(1)。
# 4.1. 构造解释报告数据框
feature_names = X.columns
shap_df = pd.DataFrame({
'Feature': feature_names,
'Value': rejected_instance.values,
'SHAP_Contribution': shap_values_class_1
})
# 4.2. 筛选和排序负面贡献(导致拒绝的原因)
# 筛选出 SHAP 贡献为负的特征,因为它们将预测结果推向拒绝(0)
negative_contributions = shap_df[shap_df['SHAP_Contribution'] < 0].copy()
# 绝对值排序,找出贡献最大的拒绝因素
negative_contributions['Absolute_Contribution'] = negative_contributions['SHAP_Contribution'].abs()
negative_contributions = negative_contributions.sort_values(by='Absolute_Contribution', ascending=False)
# 4.3. 生成合规解释报告
print("\n=======================================================")
print("| 信贷审批决策解释报告 (合规性要求) |")
print("=======================================================")
print(f"申请人ID: {rejected_index}")
print(f"最终决策: 拒绝 (预测批准概率: {probabilities[rejected_index]:.2f})")
print(f"平均批准概率 (基线): {base_value:.4f}\n")
print("拒绝的主要原因 (Contribution to Denial):")
# 打印前N个负面贡献最大的特征
for index, row in negative_contributions.head(3).iterrows():
reason = f"- 您的 {row['Feature']} ({row['Value']:.2f}) 显著降低了您的批准概率,贡献度: {-row['SHAP_Contribution']:.4f}"
print(reason)
print("\n--- 摘要 ---")
print(f"该模型从平均批准概率 {base_value:.4f} 开始,由于上述因素的负面累积贡献(总和为 {-np.sum(negative_contributions['SHAP_Contribution']):.4f}),最终导致批准概率降至 {probabilities[rejected_index]:.4f},因此决策为拒绝。")
print("=======================================================")
# 可视化(仅用于调试和内部理解)
# shap.initjs()
# shap.force_plot(base_value, shap_values_class_1, rejected_instance)
通过上述步骤,我们不仅获得了单个决策的精确SHAP值,还将其转化成了业务和合规部门可以理解的语言。这种方法确保了模型在部署后,对于每一次关键决策都能提供透明、可审计的解释。
汤不热吧