3、坏样本数据清洗:缺失值处理、异常值检测与处理、重复数据去重、数据标准化

坏样本归因的准确性高度依赖数据质量。原始风控样本通常包含缺失值、异常值、重复记录和量纲不一致等问题,直接建模会导致归因偏差。本章系统讲解坏样本清洗的四大核心环节,确保进入归因模型的数据干净、可靠。

3.1 缺失值处理

缺失值在风控样本中普遍存在,原因包括用户未填写、系统采集失败、数据同步延迟等。处理策略需结合缺失率、业务含义和变量重要性。

缺失率范围 推荐策略 适用场景
< 5% 直接删除(行删除)或均值/中位数填充 随机缺失,样本量充足
5% – 20% 统计填充(均值/中位数/众数)或模型预测填充 变量分布稳定,缺失机制可忽略
20% – 50% 增加“缺失指示变量” + 中位数填充 缺失可能包含信息(如用户刻意隐瞒)
> 50% 删除该变量,或转为二值特征(是否缺失) 变量信息量极低,易引入噪声
风控经验:对于“收入”、“负债”等强预测力变量,即使缺失率较高(30%-40%),也建议保留并增加缺失标志位,因为“用户未填写收入”本身可能是一个坏样本信号。

3.2 异常值检测与处理

异常值会严重扭曲归因分析中的统计量和模型权重。风控场景中,异常值可能来自数据录入错误、设备异常或极端的欺诈行为。常用检测方法包括:

  • Z-Score 方法:假设数据服从正态分布,|Z| > 3 视为异常。适用于对称分布变量。
  • IQR 四分位距法:超出 Q1 - 1.5×IQR 或 Q3 + 1.5×IQR 为异常。对偏态分布更稳健。
  • 孤立森林(Isolation Forest):基于树模型的无监督检测,适合高维数据。
  • 业务规则阈值:如“年龄 > 120 岁”、“单日申请次数 > 50”直接判定异常。
处理策略对比:
  • 截尾(Winsorize):将异常值替换为边界值(如 99% 分位数),保留样本量。
  • 删除:仅当异常值明确为录入错误且比例 < 1% 时使用。
  • 单独分组:将异常值作为独立类别编码,用于归因分析中的“极端行为”识别。
异常值检测与处理流程 原始坏样本数据 Z-Score 检测 IQR 四分位距法 孤立森林 业务规则阈值 截尾(Winsorize) 删除异常记录 单独分组编码 清洗后坏样本数据集 建议:先做业务规则阈值检测,再使用统计方法,避免误杀真实欺诈样本

3.3 重复数据去重

重复记录会导致坏样本被重复计数,高估特定风险特征的权重。风控数据中的重复来源包括:

  • 完全重复:所有字段完全相同,通常由系统重试或数据合并错误导致。
  • 关键字段重复:身份证号、手机号、设备ID相同,但其他字段略有差异(如申请时间不同)。
  • 近似重复:文本字段(如地址、公司名)存在拼写差异但指向同一实体。
重复类型 去重策略 保留规则
完全重复 直接删除重复行 保留任意一条
关键字段重复 按用户ID分组,保留最新一条 保留申请时间最近或信息最完整的记录
近似重复 使用编辑距离或Jaccard相似度聚类 保留置信度最高的记录,其余标记为可疑
注意:在坏样本归因中,不要盲目删除所有重复记录。如果同一用户短期内多次申请且均为坏样本,这本身可能是“多头借贷”或“欺诈试探”的重要特征,应保留并生成“重复申请次数”衍生变量。

3.4 数据标准化

坏样本归因通常涉及多个量纲不同的变量(如年龄、收入、逾期天数)。标准化可消除量纲影响,使模型系数和归因贡献度可比。常用方法:

  • Z-Score 标准化:\( x' = \frac{x - \mu}{\sigma} \),适用于数据近似正态分布。
  • Min-Max 归一化:\( x' = \frac{x - \min}{\max - \min} \),将数据映射到 [0,1] 区间,对异常值敏感。
  • Robust 标准化:\( x' = \frac{x - \text{median}}{\text{IQR}} \),使用中位数和四分位距,对异常值鲁棒。
三种标准化方法对比 原始坏样本特征 Z-Score 标准化 Min-Max 归一化 Robust 标准化 无量纲化特征矩阵
风控场景推荐:
  • 对于收入、负债等长尾分布特征,优先使用 Robust 标准化,避免极端值主导归因结果。
  • 对于年龄、授信额度等分布较均匀的特征,使用 Z-Score 标准化 即可。
  • Min-Max 归一化适合后续需要固定区间输入的模型(如神经网络),但需先处理异常值。

3.5 清洗顺序与代码示例

建议按照以下流水线顺序执行数据清洗,避免后续步骤受前序未处理问题影响:

  1. 去重 → 2. 异常值检测与处理 → 3. 缺失值处理 → 4. 数据标准化
import pandas as pd
import numpy as np
from scipy import stats

# 加载坏样本数据
df = pd.read_csv('bad_samples.csv')

# 1. 去重:基于用户ID保留最新记录
df = df.sort_values('apply_time').drop_duplicates(subset='user_id', keep='last')

# 2. 异常值处理:IQR 截尾
Q1 = df['income'].quantile(0.25)
Q3 = df['income'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df['income'] = df['income'].clip(lower=lower_bound, upper=upper_bound)

# 3. 缺失值处理:中位数填充 + 缺失标志
df['income_missing'] = df['income'].isna().astype(int)
df['income'] = df['income'].fillna(df['income'].median())

# 4. 标准化:Robust 标准化
median_income = df['income'].median()
iqr_income = df['income'].quantile(0.75) - df['income'].quantile(0.25)
df['income_scaled'] = (df['income'] - median_income) / iqr_income
关键提醒:清洗参数(如中位数、IQR、截尾边界)必须基于训练集计算,并应用到验证集和测试集,避免数据泄露。在坏样本归因项目中,建议将清洗逻辑封装为函数,确保线上线下一致性。