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 策略(如均值填充兜底)。
缺失值处理策略决策流程 原始数据含缺失值 缺失率 < 1% 且 MCAR? 是 行删除 否 需填充处理 缺失是否有规律? 否(随机缺失) 均值/中位数/众数填充 是(有规律) 模型预测填充

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)就完成格式标准化,不要在建模阶段反复清洗。建立数据质量监控看板,每日检查格式异常比例。

4.4 本章小结