4. 数据清洗基础:缺失值处理、重复值处理与格式统一
在风控建模中,原始数据几乎不可能直接用于训练。缺失值、重复记录和格式不一致是三个最常见的“脏数据”问题。本章将系统讲解这三类问题的处理策略,并给出风控场景下的实战建议。
核心原则:数据清洗的目标不是“消除所有异常”,而是让数据分布尽可能接近真实业务状态,避免因清洗不当引入偏差或信息泄露。
4.1 缺失值处理
缺失值在风控特征中普遍存在,例如用户未填写职业信息、征信查询记录为空、设备指纹采集失败等。处理方式可分为三类:删除、填充、模型预测。
4.1.1 删除缺失值
适用于缺失比例极低(如 < 1%)或缺失完全随机(MCAR)的场景。删除方式包括:
- 行删除(listwise deletion):直接删除含缺失值的样本。适用于样本量充足、缺失率低的情况。
- 列删除(variable deletion):删除缺失率超过阈值(如 70%)的特征。风控中常对“信息完整度”设置硬性门槛。
| 删除方式 | 适用场景 | 风控注意事项 |
|---|---|---|
| 行删除 | 缺失率 < 1%,样本量 > 10万 | 避免删除后导致好坏样本比例失衡 |
| 列删除 | 缺失率 > 70%,且无业务含义 | 需确认该特征是否在线上仍会缺失 |
4.1.2 均值/中位数/众数填充
这是最常用的填充方法,简单高效,但可能扭曲分布。风控场景中推荐按以下规则选择:
- 数值型特征:若分布近似正态,用均值填充;若存在长尾或异常值,用中位数填充。
- 分类型特征:用众数填充,或将“缺失”单独作为一个类别(如
unknown)。 - 时间序列特征:用前向填充(ffill)或后向填充(bfill),保持时序连贯性。
风控实战技巧:对于收入、负债率等敏感数值特征,建议同时生成“是否缺失”的哑变量(dummy flag),让模型自行学习缺失模式。
4.1.3 模型预测填充
当缺失值具有较强规律性时,可用其他特征作为输入,预测缺失值。常用方法包括:
- KNN 填充:基于相似样本的均值或众数填充,适合特征间相关性较强的场景。
- 回归/分类模型填充:用线性回归、随机森林或 XGBoost 预测缺失值。注意需避免数据泄露——预测时只能用训练集内的非缺失样本。
- 多重插补(MICE):通过迭代建模生成多个填充版本,适合学术研究,但在工业风控中因计算成本较高而使用较少。
注意:模型预测填充在训练集上表现良好,但线上推理时若输入特征也缺失,则无法实时预测。生产环境中需提前设计 fallback 策略(如均值填充兜底)。
4.2 重复值处理
重复记录会导致模型对某些样本过度学习,降低泛化能力。风控数据中的重复来源包括:用户重复申请、数据采集异常、多数据源合并未去重等。
4.2.1 完全重复与部分重复
- 完全重复:所有字段值完全相同。直接保留一条,删除其余。
- 部分重复:关键字段(如身份证号、手机号)相同,但其他字段有差异。需根据业务规则处理:例如保留最新一条、保留信息最完整的一条、或取均值。
4.2.2 风控场景特殊处理
在信贷风控中,同一用户短期内多次申请贷款(多头借贷)是重要风险信号。此时不应简单去重,而应:
- 生成“近30天申请次数”等聚合特征。
- 保留首次申请记录作为样本,将后续申请标记为“重复申请”并单独分析。
去重代码示例(Python):
import pandas as pd
# 完全重复删除
df = df.drop_duplicates()
# 按身份证号去重,保留最新一条
df = df.sort_values('apply_date').drop_duplicates(subset='id_card', keep='last')
# 生成重复次数特征
df['dup_count'] = df.groupby('id_card')['id_card'].transform('count')
4.3 格式统一
格式不一致会直接导致特征无法对齐或模型报错。常见问题包括:
| 数据类型 | 常见格式问题 | 统一方法 |
|---|---|---|
| 日期时间 | 2024/01/01、2024-01-01、01/01/2024 | 统一转为 YYYY-MM-DD 或时间戳 |
| 数值 | 含千分位逗号、货币符号、百分比 | 正则提取数字,转为 float |
| 分类 | 大小写混用、空格、同义词(如“男”与“M”) | 映射为标准字典,去除首尾空格 |
| 地址/手机号 | 区号格式不统一、含特殊字符 | 正则清洗,提取关键字段 |
3.1 日期格式统一实战
风控特征中常需计算“年龄”、“距离上次申请天数”等衍生变量,日期格式必须统一。推荐使用 pandas.to_datetime() 并指定 format 参数以提高解析速度。
import pandas as pd
# 混合格式日期列
df['date'] = pd.to_datetime(df['date_raw'], format='%Y-%m-%d', errors='coerce')
# 提取特征
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day_of_week'] = df['date'].dt.dayofweek
3.2 分类标签统一实战
对于“职业”、“学历”等分类特征,建议建立标准映射字典,并在清洗阶段统一转换。
# 职业映射字典
occupation_map = {
'公务员': 'government',
'事业单位': 'government',
'企业职员': 'corporate',
'私营业主': 'self_employed',
'自由职业': 'freelance',
'其他': 'other'
}
df['occupation_std'] = df['occupation'].str.strip().map(occupation_map)
格式统一最佳实践:在数据接入层(ETL)就完成格式标准化,不要在建模阶段反复清洗。建立数据质量监控看板,每日检查格式异常比例。