缺失值产生机制:MCAR、MAR、MNAR 原理与风控案例
在风控数据质量治理中,缺失值并非随机噪声,其背后往往隐藏着特定的数据生成逻辑。理解缺失值的产生机制,是选择正确填充策略、避免模型偏差的前提。本节将系统讲解三种缺失机制:完全随机缺失(MCAR)、随机缺失(MAR)和非随机缺失(MNAR),并结合风控场景给出典型案例。
三种缺失机制的核心定义
| 机制 | 英文全称 | 核心定义 | 缺失概率与数据关系 |
|---|---|---|---|
| MCAR | Missing Completely At Random | 缺失完全独立于观测数据和未观测数据 | 缺失概率 = 常数,与任何变量无关 |
| MAR | Missing At Random | 缺失依赖于已观测到的其他变量,但与缺失变量本身的值无关 | 缺失概率 = f(已观测变量),与缺失变量无关 |
| MNAR | Missing Not At Random | 缺失依赖于缺失变量本身的值(即使控制了其他变量) | 缺失概率 = f(缺失变量本身) |
风控提示: 在信贷风控建模中,MNAR 是最危险但最常见的缺失机制。例如,高逾期风险的客户更可能“故意”不填写收入字段,导致缺失值本身成为风险信号。
MCAR:完全随机缺失
原理: 数据缺失完全是一个随机事件,与任何已知或未知的特征无关。缺失数据可以看作是完整数据集的一个简单随机子样本。
风控案例:
- 系统故障: 某风控系统在 2024-03-15 14:00–14:05 期间因网络抖动,随机丢失了 0.3% 的申请记录中的“征信查询次数”字段。该故障与客户资质、申请时间(除该5分钟外)均无关。
- 传输丢包: 第三方数据源在接口调用时,因网络拥塞随机丢弃了约 0.1% 的数据包,导致部分客户的“社保缴纳月数”字段缺失。
处理策略: 由于 MCAR 不会引入系统性偏差,可以直接删除缺失样本(若缺失率低),或使用均值/中位数填充。但风控场景中,MCAR 实际占比通常不足 5%。
MAR:随机缺失
原理: 缺失概率依赖于其他已观测到的变量,但与缺失变量本身的值无关。例如,高收入群体更倾向于完整填写收入信息,而低收入群体可能因隐私顾虑而跳过该字段。
风控案例:
- 年龄与收入缺失: 在信贷申请数据中,年龄字段完整,但“月收入”字段缺失。分析发现,年龄 < 25 岁的申请人中,收入缺失率为 12%;年龄 ≥ 25 岁的申请人中,收入缺失率仅为 3%。缺失概率依赖于已观测的“年龄”变量,但与申请人真实的收入水平无关。
- 学历与职业信息: 学历为“高中及以下”的申请人,其“单位性质”字段缺失率(18%)显著高于学历为“本科及以上”的申请人(5%)。缺失概率依赖于已观测的“学历”变量。
处理策略: 不能简单删除,否则会引入选择偏差。应使用基于已观测变量的模型进行填充,如回归插补、多重插补(MICE)或基于决策树的填充方法。
MNAR:非随机缺失
原理: 缺失概率直接依赖于缺失变量本身的值。这是最复杂、最难处理的缺失机制,因为缺失本身携带了信息。
风控案例:
- 逾期天数缺失: 在贷后管理数据中,部分客户的“当前逾期天数”字段缺失。进一步分析发现,缺失的客户实际上已经逾期超过 90 天(处于核销流程中),系统因状态异常未正常记录该字段。缺失与否直接由“逾期天数”本身的值决定。
- 收入隐瞒: 高风险客户(真实收入极低或不稳定)更倾向于不填写“月收入”字段,以避免被拒贷。缺失概率与收入水平本身呈负相关。
- 征信查询次数: 多头借贷严重的客户(征信查询次数极高),其部分征信报告可能因机构限制而无法完整获取,导致“近3个月查询次数”字段缺失。
模型偏差警告: 在 MNAR 场景下,如果直接使用均值填充或删除缺失样本,会严重低估高风险客户的特征分布,导致风控模型对坏客户的识别能力大幅下降。此时,缺失值本身应作为一个重要的风险特征参与建模。
三种机制在风控中的识别与应对
实际风控数据中,三种机制往往混合存在。以下表格总结了识别方法和应对策略:
| 机制 | 识别方法 | 风控应对策略 |
|---|---|---|
| MCAR | 分组检验:将数据按缺失/非缺失分组,检验其他变量均值是否存在显著差异(t检验/卡方检验) | 直接删除(缺失率 < 5%);均值/中位数填充 |
| MAR | 逻辑回归:以缺失标志为因变量,其他完整变量为自变量,检验回归系数显著性 | 多重插补(MICE);基于模型的回归插补;保留缺失标志作为特征 |
| MNAR | 敏感性分析:假设不同的缺失机制,评估模型结果稳定性;领域专家判断 | 将缺失值编码为独立类别;使用 Heckman 选择模型;构建缺失指示变量作为特征 |
缺失机制与风控模型偏差的关系
Python 实战:模拟三种缺失机制
以下代码演示如何在风控模拟数据中生成 MCAR、MAR 和 MNAR 三种缺失模式,帮助理解其生成逻辑:
import pandas as pd
import numpy as np
# 生成模拟风控数据
np.random.seed(42)
n = 10000
data = pd.DataFrame({
'age': np.random.randint(22, 60, n),
'income': np.random.normal(15000, 5000, n).clip(3000, 50000),
'credit_score': np.random.randint(300, 850, n),
'overdue_days': np.random.poisson(5, n) # 逾期天数
})
# 1. MCAR:完全随机缺失(系统故障)
data_mcar = data.copy()
mask_mcar = np.random.random(n) < 0.05 # 5% 随机缺失
data_mcar.loc[mask_mcar, 'credit_score'] = np.nan
# 2. MAR:随机缺失(缺失依赖于年龄)
data_mar = data.copy()
# 年龄 < 30 的申请人,收入缺失概率 15%;年龄 ≥ 30 的,缺失概率 3%
prob_mar = np.where(data_mar['age'] < 30, 0.15, 0.03)
mask_mar = np.random.random(n) < prob_mar
data_mar.loc[mask_mar, 'income'] = np.nan
# 3. MNAR:非随机缺失(缺失依赖于逾期天数本身)
data_mnar = data.copy()
# 逾期天数 > 10 的客户,缺失概率 80%;否则 2%
prob_mnar = np.where(data_mnar['overdue_days'] > 10, 0.80, 0.02)
mask_mnar = np.random.random(n) < prob_mnar
data_mnar.loc[mask_mnar, 'overdue_days'] = np.nan
# 验证缺失率
print(f"MCAR - credit_score 缺失率: {data_mcar['credit_score'].isna().mean():.2%}")
print(f"MAR - income 缺失率: {data_mar['income'].isna().mean():.2%}")
print(f"MNAR - overdue_days 缺失率: {data_mnar['overdue_days'].isna().mean():.2%}")
输出示例:
MCAR - credit_score 缺失率: 5.01%
MAR - income 缺失率: 6.84%
MNAR - overdue_days 缺失率: 12.35%
MCAR - credit_score 缺失率: 5.01%
MAR - income 缺失率: 6.84%
MNAR - overdue_days 缺失率: 12.35%
风控场景中的缺失机制诊断流程
总结:风控缺失机制选择矩阵
| 缺失机制 | 典型风控场景 | 推荐填充方法 | 是否保留缺失标志 |
|---|---|---|---|
| MCAR | 系统故障、传输丢包 | 均值/中位数填充;直接删除 | 通常不需要 |
| MAR | 年龄影响收入缺失、学历影响职业信息缺失 | 多重插补(MICE);回归插补 | 建议保留 |
| MNAR | 逾期天数缺失、高风险客户隐瞒收入 | 缺失值编码为独立类别;Heckman 模型 | 必须保留 |
实战建议: 在风控建模中,建议始终保留缺失指示变量(is_missing)作为候选特征。即使初步判断为 MCAR 或 MAR,保留该标志也不会带来额外风险,反而可能在 MNAR 场景下捕获关键风险信号。