4. 拒绝推断入门:为什么需要拒绝推断、拒绝样本的偏差来源、简单拒绝推断方法(硬截断法)
4.1 为什么需要拒绝推断
在信贷额度模型中,我们通常只能观察到“通过审批”的客户表现(好坏标签),而“被拒绝”的客户则没有后续表现数据。这种样本选择偏差会导致模型在训练时只学习了通过人群的规律,却无法对拒绝人群进行有效预测。拒绝推断(Reject Inference)正是为了解决这一问题而设计的。
核心痛点: 如果直接忽略拒绝样本,模型会高估通过客户的信用水平,导致额度分配过于激进,最终增加坏账风险。
拒绝推断的核心目标:
- 纠正偏差: 将拒绝样本的潜在表现纳入模型训练,使模型更接近真实客群分布。
- 提升泛化: 避免模型在拒绝人群上“盲猜”,提高额度策略的稳健性。
- 合规要求: 监管机构(如巴塞尔协议)要求银行在模型开发中考虑拒绝推断,确保公平性和准确性。
4.2 拒绝样本的偏差来源
拒绝样本的偏差主要来源于样本选择机制。下图展示了偏差产生的完整链路:
关键认知: 拒绝样本的偏差不是随机缺失,而是与审批策略强相关的非随机缺失。如果审批策略本身有偏(例如过度依赖收入),那么拒绝人群的信用分布就会与通过人群显著不同。
4.3 简单拒绝推断方法:硬截断法
硬截断法(Hard Cutoff Method)是最直观的拒绝推断方法,适用于审批策略已经稳定、拒绝率较低的场景。其核心思路是:用通过样本训练的模型,直接对拒绝样本进行预测,然后将预测结果作为“伪标签”加入训练集。
4.3.1 硬截断法操作步骤
- 步骤1: 使用通过样本(有标签)训练初始模型 M₀。
- 步骤2: 用 M₀ 对拒绝样本进行预测,得到每个拒绝样本的违约概率 p̂。
- 步骤3: 设定一个截断阈值(如 p̂ > 0.5 视为坏样本,否则为好样本),为拒绝样本赋予伪标签。
- 步骤4: 将带伪标签的拒绝样本与原始通过样本合并,形成新训练集。
- 步骤5: 用新训练集重新训练模型 M₁,作为最终模型。
4.3.2 硬截断法的优缺点对比
| 维度 | 优点 | 缺点 |
|---|---|---|
| 实现难度 | 逻辑简单,代码量少,易于快速落地 | 对阈值敏感,需要人工调参 |
| 数据利用 | 充分利用了拒绝样本的特征信息 | 伪标签质量依赖初始模型,可能放大偏差 |
| 适用场景 | 拒绝率较低(<20%)、审批策略稳定 | 拒绝率较高时,伪标签噪声过大 |
| 模型风险 | 能一定程度缓解样本选择偏差 | 可能引入“自我实现预言”偏差 |
⚠️ 硬截断法的陷阱: 如果初始模型 M₀ 本身存在偏差(例如对某些群体预测不准),那么用 M₀ 生成的伪标签会强化这种偏差,导致最终模型 M₁ 在拒绝人群上表现更差。建议在步骤3中引入置信度筛选,只保留预测概率接近0或1的样本。
4.3.3 硬截断法流程示意图
4.3.4 硬截断法代码示例
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
# 假设已有通过样本 approved_df 和拒绝样本 rejected_df
# approved_df 包含特征 X 和标签 y (0=好, 1=坏)
# rejected_df 只包含特征 X
# 步骤1: 训练初始模型
model_0 = LogisticRegression()
model_0.fit(approved_df[['feature1', 'feature2', 'feature3']], approved_df['y'])
# 步骤2: 预测拒绝样本的违约概率
rejected_proba = model_0.predict_proba(rejected_df[['feature1', 'feature2', 'feature3']])[:, 1]
# 步骤3: 设定阈值,生成伪标签(阈值=0.5)
threshold = 0.5
rejected_df['pseudo_y'] = (rejected_proba > threshold).astype(int)
# 步骤4: 合并数据集
combined_df = pd.concat([
approved_df[['feature1', 'feature2', 'feature3', 'y']],
rejected_df[['feature1', 'feature2', 'feature3', 'pseudo_y']].rename(columns={'pseudo_y': 'y'})
], ignore_index=True)
# 步骤5: 重新训练最终模型
model_1 = LogisticRegression()
model_1.fit(combined_df[['feature1', 'feature2', 'feature3']], combined_df['y'])
print("硬截断法完成,最终模型已训练。")
实践建议: 硬截断法虽然简单,但在实际项目中常作为基线方法使用。如果拒绝率较高(>30%),建议升级为模糊展开法或两阶段模型,以获得更稳健的推断结果。