4. 简单拒绝推断方法:随机抽样法、拒绝样本直接赋值法、拒绝样本加权法

好,咱们进入正题。拒绝推断这个事儿,说白了就是跟「未知」较劲。你想想看,银行只给通过的人放贷,那被拒的那些人,到底会不会违约?没人知道。但模型又必须学这个信息,怎么办?

我刚开始做评分卡那会儿,也天真地以为「拒绝样本扔了就行」。后来被老板骂了一顿才明白——拒绝样本里藏着巨大的选择偏差。你不处理它,模型上线后一跑,坏账率直接翻倍。嗯,这都是血泪教训。

今天咱们先聊三种最简单的拒绝推断方法。它们不复杂,但很实用。我个人习惯在项目初期先用它们探探路。

4.1 随机抽样法

这个方法最直白。你从拒绝样本里随机抽一部分,直接扔进训练集。然后给它们打上标签——通常是「好人」或者「未知」。具体怎么打,看你的业务场景。

我见过不少团队这么干。为什么?因为快。你想想看,一个模型迭代周期就两周,哪有时间搞复杂的半监督学习?随机抽样,简单粗暴,先跑起来再说。

核心思路: 假设拒绝样本和通过样本的分布是「近似」的。随机抽一部分,强行让模型看到拒绝人群的样子。

但这里有个坑。我曾经在一个现金贷项目里试过随机抽样,结果模型上线后,通过率下降了5个点。为什么?因为拒绝样本里其实有很多「硬拒绝」——那些征信黑名单的人。你把他们抽进来当好人,模型就学歪了。

注意: 随机抽样法只适合「软拒绝」场景。也就是那些分数接近通过线、被人工否决的样本。硬拒绝样本千万别往里塞。

具体操作步骤很简单:

  1. 统计拒绝样本总量,比如有10万条
  2. 设定抽样比例,比如10%
  3. 随机抽取1万条
  4. 给这1万条打上「好人」标签(或者保留为空,看算法)
  5. 合并到训练集里重新训练

代码实现也不复杂:

import pandas as pd
import numpy as np

# 假设 reject_df 是拒绝样本
sample_rate = 0.1
sample_size = int(len(reject_df) * sample_rate)

# 随机抽样
sampled_reject = reject_df.sample(n=sample_size, random_state=42)

# 打标签:假设0是好人
sampled_reject['label'] = 0

# 合并到训练集
train_augmented = pd.concat([train_df, sampled_reject], ignore_index=True)
小技巧: 我建议抽样比例不要超过20%。抽太多会把拒绝样本的噪声带进来,反而降低模型区分度。

4.2 拒绝样本直接赋值法

这个方法比随机抽样「聪明」一点点。它不随机抽,而是给每个拒绝样本直接赋一个标签。怎么赋?用你已有的评分卡去打分。

具体来说:

  • 先用通过样本训练一个初始模型
  • 用这个模型去预测拒绝样本的违约概率
  • 设定一个阈值,比如概率大于0.7的,标记为「坏人」
  • 概率小于0.3的,标记为「好人」
  • 中间的,扔掉或者保留为不确定

我当年在一个信用卡项目里用过这招。当时拒绝样本有20万条,直接赋值后,模型AUC提升了0.03。效果还不错。

核心逻辑: 用模型自己来「猜」拒绝样本的标签。虽然不完美,但比随机抽样更有依据。

但这里有个明显的悖论——你用一个有偏的模型去预测有偏的样本,结果能准吗?说白了,这就是「用错误去纠正错误」。所以这个方法只适合做快速验证,不能作为最终方案。

代码示例:

from sklearn.ensemble import RandomForestClassifier

# 训练初始模型
model = RandomForestClassifier()
model.fit(X_train, y_train)

# 预测拒绝样本
reject_proba = model.predict_proba(X_reject)[:, 1]

# 直接赋值
reject_label = np.where(reject_proba > 0.7, 1, 
                        np.where(reject_proba < 0.3, 0, np.nan))

# 只保留有明确标签的样本
valid_idx = ~np.isnan(reject_label)
X_reject_valid = X_reject[valid_idx]
y_reject_valid = reject_label[valid_idx]
避坑指南: 我曾经试过把阈值设得太宽(0.4-0.6都扔掉),结果拒绝样本利用率不到30%。模型几乎没学到新信息。建议阈值设得紧一点,比如0.2-0.8,多留一些样本。

4.3 拒绝样本加权法

这个方法我最常用。它不改变标签,而是给样本加权重。核心思想是:拒绝样本的信息量不如通过样本大,所以给它更低的权重

怎么算权重?常见做法有两种:

方法 权重计算 适用场景
逆概率加权 权重 = 1 / 通过概率 拒绝机制已知
启发式加权 权重 = 0.3 ~ 0.5 拒绝机制未知

我个人习惯用启发式加权。为什么?因为大多数银行的拒绝机制都是黑箱——你根本不知道审批经理到底看了什么。逆概率加权虽然理论漂亮,但实际用起来一堆假设,很容易翻车。

具体操作:

  • 通过样本权重设为1.0
  • 拒绝样本权重设为0.3 ~ 0.5
  • 训练时,模型会更关注通过样本,但也不会完全忽略拒绝样本

代码实现:

# 构建权重数组
weights = np.ones(len(X_train))
reject_weight = 0.3  # 拒绝样本权重

# 假设 reject_idx 是拒绝样本在训练集中的索引
weights[reject_idx] = reject_weight

# 训练时传入权重
model.fit(X_train, y_train, sample_weight=weights)
经验之谈: 权重设多少合适?我一般先试0.3。如果模型在验证集上表现变差,就调高到0.5。如果拒绝样本质量太差(比如全是硬拒绝),就降到0.1。没有固定值,全靠调。

4.4 三种方法对比

咱们用一张表总结一下:

方法 优点 缺点 我推荐的使用场景
随机抽样法 简单、快、容易实现 可能引入噪声,硬拒绝场景失效 项目初期快速验证
直接赋值法 有依据,比随机抽样更合理 存在循环论证,模型偏差会放大 拒绝样本量大的时候做初步筛选
加权法 不改变标签,灵活可控 权重需要手动调,没有理论最优解 大多数实际项目,我最常用

4.5 核心逻辑流程图

下面这张图展示了三种方法的整体流程。你可以看到,它们都是从「拒绝样本池」出发,但处理方式完全不同。

简单拒绝推断方法流程对比 拒绝样本池 随机抽样法 直接赋值法 加权法 随机抽取10%样本 打上「好人」标签 合并到训练集 用初始模型预测 根据概率阈值赋值 保留明确标签样本 设定拒绝样本权重 通常0.3~0.5 训练时传入权重 更新后的评分卡模型

你看,三种方法最终都指向同一个目标——更新评分卡模型。但路径不同,代价也不同。随机抽样法最快但最粗糙,直接赋值法有依据但容易过拟合,加权法最灵活但需要调参。

我的建议: 如果你时间紧、任务重,先用加权法。它不容易翻车,而且调参空间大。等模型稳定了,再尝试更高级的方法,比如半监督学习或两阶段法。

好了,这三种简单方法就聊到这儿。它们虽然「简单」,但绝不是「简陋」。在实际项目中,我见过不少团队用加权法就搞定了80%的问题。别小看它们。

专注资料整理