3. 数据探查与质量分析:缺失值分析、异常值检测、数据分布一致性检查、数据质量报告

在风控建模中,数据质量直接决定模型的上限。原始数据通常包含缺失、异常、分布偏移等问题,若不加以处理,会导致模型训练不稳定、泛化能力差,甚至上线后出现严重的预测偏差。本章将系统讲解数据探查与质量分析的四大核心环节:缺失值分析、异常值检测、数据分布一致性检查以及数据质量报告的生成。

核心原则:数据探查不是一次性工作,而是贯穿特征工程全周期的迭代过程。每次特征衍生或样本构建后,都应重新执行质量检查。

3.1 缺失值分析

缺失值分析的目标是识别缺失模式、量化缺失比例,并判断缺失机制(MCAR、MAR、MNAR)。

3.1.1 缺失值统计指标

指标 定义 风控场景意义
缺失率 缺失样本数 / 总样本数 > 50% 的特征通常直接剔除;> 30% 需谨慎处理
缺失模式 单变量缺失 / 多变量联合缺失 联合缺失可能暗示数据采集流程缺陷
缺失与目标变量关联 缺失组 vs 非缺失组的逾期率差异 若差异显著,缺失本身可能成为强特征

3.1.2 缺失机制判断

  • MCAR(完全随机缺失):缺失与任何变量无关。例如系统随机丢包。可直接删除或简单填充。
  • MAR(随机缺失):缺失依赖于其他观测变量。例如高收入群体更少填写收入字段。需用模型预测填充。
  • MNAR(非随机缺失):缺失依赖于缺失值本身。例如逾期用户故意不填联系方式。需业务经验介入。
实战建议:在风控场景中,大部分缺失属于 MAR 或 MNAR。建议对缺失率 > 5% 的特征,先做缺失指示变量(is_null),再结合业务逻辑选择填充策略。

3.2 异常值检测

异常值检测用于识别与正常样本分布偏离过大的数据点。风控中的异常值可能代表欺诈、录入错误或极端信用行为。

3.2.1 常用检测方法对比

方法 适用场景 优点 缺点
Z-Score 近似正态分布 计算简单,阈值明确 对偏态分布不鲁棒
IQR(箱线图) 任意分布 不受极端值影响 对样本量敏感
孤立森林 高维数据 线性时间复杂度 对局部异常不敏感
DBSCAN 密度聚类场景 可发现任意形状异常 参数调优困难

3.2.2 异常值处理策略

  • 截尾(Winsorize):将超出阈值的值替换为阈值边界值,保留样本量。
  • 删除:仅当确认异常为录入错误或明显噪声时使用。
  • 分箱:将连续变量离散化,弱化异常值影响。
  • 缺失化:将异常值视为缺失,统一走缺失处理流程。
注意:在风控建模中,不要轻易删除异常样本。某些异常值(如极低的收入配合极高的负债)可能是欺诈的强信号,应保留并单独编码。

3.3 数据分布一致性检查

分布一致性检查用于验证训练集、验证集、测试集以及线上实时数据是否来自同一分布。分布偏移是风控模型失效的主要原因之一。

3.3.1 常用统计检验方法

检验方法 适用变量类型 原假设
KS 检验 连续变量 两组样本分布相同
卡方检验 分类变量 两组样本分布无显著差异
PSI(群体稳定性指标) 连续/分箱变量 PSI < 0.1 表示稳定
JS 散度 概率分布 对称度量,值越小越相似

3.3.2 PSI 计算与解读

import numpy as np

def calculate_psi(expected, actual, bins=10):
    # 将 expected 和 actual 分箱
    expected_bins = np.histogram(expected, bins=bins)[0] + 1e-6
    actual_bins = np.histogram(actual, bins=bins)[0] + 1e-6
    
    # 计算占比
    expected_pct = expected_bins / expected_bins.sum()
    actual_pct = actual_bins / actual_bins.sum()
    
    # PSI 公式
    psi = np.sum((actual_pct - expected_pct) * np.log(actual_pct / expected_pct))
    return psi

# 示例:训练集 vs 测试集
psi_value = calculate_psi(train_feature, test_feature)
print(f"PSI = {psi_value:.4f}")
# PSI < 0.1: 稳定;0.1-0.25: 需关注;> 0.25: 严重偏移
风控实践:建议按月或按周监控 PSI。当 PSI > 0.25 时,需立即排查原因(客群变化、政策调整、数据源变更),并考虑模型重训或特征重构。

3.4 数据质量报告

数据质量报告是数据探查的最终交付物,用于记录所有发现的问题、处理建议以及决策依据。一份完整的报告应包含以下模块:

  1. 数据概览:样本量、特征数、数据类型分布、内存占用。
  2. 缺失分析:每个特征的缺失率、缺失模式热力图、缺失与目标变量交叉表。
  3. 异常检测:每个连续特征的异常值比例、异常样本列表(抽样展示)。
  4. 分布检查:训练/测试/线上数据的 PSI 矩阵、KS 检验 p 值汇总。
  5. 处理建议:针对每个问题特征给出明确的处理策略(删除/填充/变换/保留)。
  6. 风险等级:将特征按质量分为 A(可直接使用)、B(需处理)、C(建议剔除)三级。
数据质量分析全流程 原始数据 缺失值分析 缺失率 / 缺失模式 / 缺失机制 异常值检测 Z-Score / IQR / 孤立森林 分布一致性检查 KS / PSI / JS 散度 数据质量报告 问题汇总 / 处理建议 / 风险等级 特征保留 / 变换 特征剔除 数据源回溯修复 说明:数据质量分析是迭代过程,每次特征衍生或样本更新后均需重新执行

3.5 实战:自动化数据质量报告生成

以下代码展示如何用 Python 快速生成数据质量报告的核心指标:

import pandas as pd
import numpy as np

def generate_quality_report(df, target_col=None):
    report = []
    for col in df.columns:
        row = {'特征': col, '数据类型': df[col].dtype}
        
        # 缺失分析
        row['缺失率'] = df[col].isnull().mean()
        
        # 异常检测(仅数值型)
        if pd.api.types.is_numeric_dtype(df[col]):
            q1 = df[col].quantile(0.25)
            q3 = df[col].quantile(0.75)
            iqr = q3 - q1
            lower = q1 - 1.5 * iqr
            upper = q3 + 1.5 * iqr
            row['异常值比例'] = ((df[col] < lower) | (df[col] > upper)).mean()
        else:
            row['异常值比例'] = np.nan
        
        # 唯一值比例(分类变量)
        if df[col].nunique() < 50:
            row['唯一值数'] = df[col].nunique()
        else:
            row['唯一值数'] = '>50'
        
        report.append(row)
    
    report_df = pd.DataFrame(report)
    report_df['风险等级'] = pd.cut(
        report_df['缺失率'],
        bins=[-0.001, 0.05, 0.3, 1.0],
        labels=['A-低风险', 'B-需关注', 'C-高风险']
    )
    return report_df

# 使用示例
# quality_df = generate_quality_report(data, target_col='is_default')
# quality_df.to_csv('data_quality_report.csv', index=False)
交付标准:数据质量报告应包含可执行的处理建议,而非仅罗列统计数字。例如:“特征 income 缺失率 35%,建议:① 创建缺失指示变量;② 用职业+学历分组中位数填充;③ 若填充后 PSI > 0.2,考虑剔除。”

3.6 本章小结

  • 缺失值分析需同时关注缺失率、缺失模式和缺失机制,风控场景建议保留缺失指示变量。
  • 异常值检测应结合业务理解,欺诈场景中的异常值往往是重要信号,不宜简单删除。
  • 分布一致性检查是模型稳定性的生命线,PSI 和 KS 检验应纳入日常监控体系。
  • 数据质量报告是数据探查的标准化输出,需包含问题定位、处理建议和风险等级,便于跨团队协作。