缺失值处理:删除、填充与标记策略
说实话,缺失值处理这事儿,看着简单,坑却不少。我记得刚开始做风控模型那会儿,总觉得把缺失值删干净就完事了。结果呢?模型上线后,一批本该被拦截的坏客户全放了进来。为什么?因为那些缺失值背后,其实隐藏着风险信号。
缺失值不是简单的"数据丢了"。它往往意味着:客户不愿意填、系统没采到、或者这个特征本身对这类客户不适用。每种情况,处理方式都不一样。
缺失值从哪来?先搞清楚根源
我个人习惯,拿到数据第一件事不是急着处理缺失值,而是先分析缺失的原因。不同原因,处理方式天差地别。
| 缺失类型 | 实际含义 | 风控中的常见场景 |
|---|---|---|
| 完全随机缺失 | 缺失与数据本身无关 | 系统偶尔漏采、传输丢包 |
| 随机缺失 | 缺失与其他已知变量相关 | 高收入人群更少填"月支出"字段 |
| 非随机缺失 | 缺失与缺失值本身直接相关 | 逾期客户故意不填收入、联系人信息 |
明白了吧?非随机缺失在风控里最常见,也最危险。那些不填信息的人,往往就是高风险人群。
策略一:删除——简单但代价大
删除是最直接的办法。但什么时候能用?
- 整行删除:缺失比例低于5%,且确认是随机缺失。比如100万样本里只有2万条缺了某个字段,直接删掉影响不大。
- 整列删除:某个特征缺失率超过70%,而且这个特征业务意义不大。比如"客户星座"字段,80%是空值,删就删了。
⚠ 千万别踩这个坑
我曾经在一个多头借贷预测项目里,把缺失"联系人电话"的行全删了。结果模型在测试集上AUC 0.83,上线后却只有0.61。后来复盘发现——逾期客户恰恰是最不愿意留电话的那群人。删除操作,把最关键的坏样本一起扔掉了。
记住:风控里,缺失本身可能就是强特征!
策略二:填充——保样本但会引入偏差
我常用的填充方法有这些,每个都有适用边界:
| 填充方法 | 怎么做 | 风控中的坑 |
|---|---|---|
| 均值/中位数 | 用该特征的平均值或中位数代替 | 把异常客户拉回"正常"范围,掩盖风险特征 |
| 众数填充 | 用出现频率最高的值填充 | 适用于类别特征,如"学历"缺失用"本科"填充 |
| 前向后向填充 | 用相邻记录的值填充 | 适用时序数据,不适用于跨客户填充 |
| 模型预测填充 | 用回归/分类模型预测缺失值 | 计算量大,且可能强化已有模式 |
| 多重插补 | 生成多个填充版本取平均 | 统计严谨,但风控场景中上线复杂 |
💡 我的一个实操建议
你想想看,风控模型最终是要做分箱的。如果某个特征缺失率在5%-15%之间,我个人喜欢用条件均值填充——按目标变量(好人/坏人)分组,分别计算均值再填充。这样做的好处是,保留了不同风险群体之间的差异,不会把坏人的特征拉到好人的水平线上。
策略三:缺失标记——风控场景的秘密武器
这招在风控里特别有用。说白了,就是把"是否缺失"本身作为一个独立的信息维度。
具体操作分两步:
- 生成缺失标记变量:新增一个0/1变量,1表示该字段缺失,0表示有值。
- 对原特征填充:用均值、-1、或者其他安全值填充,保证模型能正常计算。
举个例子,特征"社保缴纳月数"有15%的缺失值。我这样处理:
# 生成缺失标记
df['社保缴纳月数_missing'] = df['社保缴纳月数'].isnull().astype(int)
# 用-1填充,让缺失值在分箱时自动归为一类
df['社保缴纳月数'] = df['社保缴纳月数'].fillna(-1)
我在几个信贷项目里验证过,增加缺失标记后,模型的KS值通常能提升3-5个百分点。为什么?因为那些"不交社保"的人,本身就是一批特殊的客群。
📌 核心结论
缺失值处理没有银弹。你需要根据场景组合使用:
- 随机缺失且量小 → 删除
- 随机缺失但量大 → 填充(条件均值优先)
- 非随机缺失 → 标记+填充(风控首选)
- 缺失率极高(>70%)→ 考虑直接删除该特征
关于缺失值处理的几个坑
- 别在分箱前做统一填充:分箱本身对缺失值也有处理能力,先填充可能破坏原始分布。
- 训练集和测试集要统一策略:测试集用训练集的均值填充,不能各自算各自的。
- 时间序列数据别用未来值填充:这在风控的贷后监控里很常见,一定要注意。
- 多重共线性:当缺失标记变量和原特征强相关时,模型可能会出问题。不过这在树模型中影响较小。
嗯,说到这其实想强调一点:缺失值处理不是"修数据",而是"理解数据"。你处理缺失值的方式,本质上就是你对自己业务假设的表达。