3. 数据质量初探:缺失值、异常值、重复值对样本代表性的影响,以及初步清洗方法

在风控建模中,样本的代表性直接决定了模型在真实业务场景中的泛化能力。然而,原始数据几乎总是存在三类常见问题:缺失值、异常值和重复值。这些问题会扭曲数据分布,导致样本偏差,进而使模型产生系统性误判。本章将系统分析这三类问题对样本代表性的影响,并给出可落地的初步清洗方法。

3.1 三类数据质量问题对样本代表性的影响

数据质量问题并非简单的“脏数据”,它们会从不同维度破坏样本的随机性和分布一致性。下表总结了核心影响机制:

问题类型 对样本代表性的影响 典型风控场景
缺失值 导致有效样本量减少;若缺失机制非随机(MNAR),会引入系统性偏差,使样本分布偏离总体 收入字段缺失(高收入群体更倾向不填),导致模型低估还款能力
异常值 拉偏统计量(均值、方差),破坏变量分箱稳定性;极端值可能掩盖正常样本的分布模式 单笔交易金额异常高(如1000万),导致额度模型分箱边界失真
重复值 人为放大某些样本的权重,造成过拟合假象;若重复样本标签不一致,会引入噪声 同一用户多次申请被重复记录,导致模型对该用户行为过度学习
关键认知: 缺失、异常、重复不是孤立问题。例如,缺失值处理不当可能产生新的异常值;异常值剔除后可能改变缺失模式。清洗策略需要全局视角,而非逐字段独立操作。

3.2 缺失值:机制识别与初步处理

3.2.1 缺失机制分类

处理缺失值前,必须判断其缺失机制。错误的假设会导致严重的样本偏差:

  • 完全随机缺失(MCAR): 缺失与任何变量无关。例如,系统随机丢包导致字段丢失。此时删除缺失样本不会引入偏差,但会损失样本量。
  • 随机缺失(MAR): 缺失与其他已观测变量有关,但与自身真实值无关。例如,高收入用户更可能填写收入字段,但收入缺失与否与收入本身无关(仅与已观测的职业等级有关)。
  • 非随机缺失(MNAR): 缺失与自身真实值有关。例如,负债率过高的用户刻意隐瞒负债数据。这是风控中最危险的情况,直接破坏样本代表性。
缺失机制决策流程 缺失值检测 缺失是否与自身值相关? MNAR 需业务干预 MCAR / MAR 可统计处理 选择清洗策略

3.2.2 初步清洗方法

根据缺失机制和业务含义,选择以下方法:

  • 删除法: 仅适用于MCAR且缺失比例<5%的场景。直接删除缺失样本或特征。
  • 统计填充: 均值/中位数/众数填充。适用于MAR且缺失比例较低(5%-20%)。注意:填充会压缩方差,需在后续建模中做标记。
  • 模型预测填充: 使用其他特征构建回归/分类模型预测缺失值。适用于MAR且特征间相关性较强。
  • 缺失指示变量: 新增二值特征标记是否缺失,保留缺失信息。适用于所有机制,尤其适合MNAR场景。
风控实践建议: 对于收入、负债等关键字段,优先使用“缺失指示变量 + 中位数填充”的组合策略。这样既保留了缺失模式信息,又避免了模型因缺失值而无法计算。

3.3 异常值:识别方法与处理策略

3.3.1 异常值识别方法

异常值识别需结合统计方法和业务规则,避免误杀正常样本:

方法 适用场景 阈值设定
Z-Score 近似正态分布 |Z| > 3
IQR(四分位距) 偏态分布、含离群点 Q1 - 1.5*IQR 或 Q3 + 1.5*IQR
业务规则 有明确业务约束 如年龄 < 18 或 > 100
孤立森林 高维数据、非线性边界 异常得分 > 0.6(可调)

3.3.2 处理策略

  • 截尾处理(Winsorization): 将异常值替换为阈值边界值。例如,将超过99%分位数的值替换为99%分位数。保留样本量,减少极端值影响。
  • 缺失化处理: 将异常值视为缺失,然后按缺失值策略处理。适用于异常值比例较低且业务上认为异常值不可信的场景。
  • 分箱处理: 将连续变量离散化,异常值落入单独箱体。例如,收入字段设置“>100万”为独立箱体。
避坑提示: 不要一次性剔除所有异常值。风控数据中,部分异常值(如极高收入、极低负债)可能代表优质客户群体。建议先做分箱观察,确认异常值群体的坏账率后再决定处理方式。

3.4 重复值:检测与去重策略

3.4.1 重复值类型

  • 完全重复: 所有字段完全相同。通常由系统重复采集或数据合并错误导致。
  • 部分重复: 关键字段(如身份证号、手机号)相同,但其他字段有差异。常见于用户多次申请、信息更新场景。

3.4.2 去重策略

场景 策略 注意事项
完全重复 保留第一条,删除其余 确认重复原因,避免误删时间序列数据
部分重复(标签一致) 保留最新记录或合并信息 按时间戳或业务优先级选择
部分重复(标签冲突) 标记为噪声,单独分析 标签冲突可能暗示数据源不一致,需溯源
实战案例: 某信贷平台发现模型在“手机号”字段上表现异常。经排查,约8%的用户存在重复申请记录,且重复样本的逾期标签不一致(一次逾期、一次正常)。去重后模型AUC提升0.03,说明重复值导致的标签噪声严重干扰了模型学习。

3.5 初步清洗流程与代码示例

以下是一个标准的数据质量初步清洗流程,适用于风控建模前的数据预处理阶段:

import pandas as pd
import numpy as np

def initial_clean(df, id_col='user_id', target_col='label'):
    """
    风控数据初步清洗函数
    """
    # 1. 重复值处理
    print(f"去重前样本量: {len(df)}")
    # 基于ID列去重,保留最新记录
    df = df.sort_values('timestamp').drop_duplicates(subset=[id_col], keep='last')
    print(f"去重后样本量: {len(df)}")
    
    # 2. 缺失值统计
    missing_ratio = df.isnull().mean()
    print("缺失比例:\n", missing_ratio[missing_ratio > 0])
    
    # 3. 异常值检测(IQR方法)
    numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()
    for col in numeric_cols:
        if col in [id_col, target_col]:
            continue
        Q1 = df[col].quantile(0.25)
        Q3 = df[col].quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        outlier_mask = (df[col] < lower_bound) | (df[col] > upper_bound)
        if outlier_mask.sum() > 0:
            print(f"{col}: 发现 {outlier_mask.sum()} 个异常值 ({outlier_mask.mean():.2%})")
            # 截尾处理
            df[col] = df[col].clip(lower=lower_bound, upper=upper_bound)
    
    # 4. 缺失值填充(中位数 + 缺失指示变量)
    for col in missing_ratio[missing_ratio > 0].index:
        df[f'{col}_is_missing'] = df[col].isnull().astype(int)
        if df[col].dtype in ['float64', 'int64']:
            df[col].fillna(df[col].median(), inplace=True)
        else:
            df[col].fillna(df[col].mode()[0], inplace=True)
    
    return df
执行建议: 上述代码应在探索性数据分析(EDA)之后、特征工程之前执行。清洗过程中记录每一步的样本量变化和字段处理日志,便于后续回溯和审计。

3.6 清洗后的样本代表性校验

清洗完成后,必须验证样本代表性是否得到改善:

  • 分布对比: 使用KS检验或卡方检验,对比清洗前后关键特征与总体(或拒绝样本)的分布差异。
  • PSI(群体稳定性指标): 计算清洗前后样本的PSI值,PSI < 0.1表示分布稳定。
  • 业务规则校验: 检查清洗后数据是否仍符合业务常识(如年龄、收入范围)。
清洗后样本代表性校验流程 清洗后样本 分布对比(KS/卡方) PSI稳定性指标 PSI < 0.1 且分布一致? 样本代表性合格 需重新评估清洗策略

通过上述校验,可以确认清洗操作是否真正改善了样本代表性,还是引入了新的偏差。如果校验不通过,需要回溯到缺失值、异常值或重复值的处理环节,调整策略后重新清洗。