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 数据质量报告
数据质量报告是数据探查的最终交付物,用于记录所有发现的问题、处理建议以及决策依据。一份完整的报告应包含以下模块:
- 数据概览:样本量、特征数、数据类型分布、内存占用。
- 缺失分析:每个特征的缺失率、缺失模式热力图、缺失与目标变量交叉表。
- 异常检测:每个连续特征的异常值比例、异常样本列表(抽样展示)。
- 分布检查:训练/测试/线上数据的 PSI 矩阵、KS 检验 p 值汇总。
- 处理建议:针对每个问题特征给出明确的处理策略(删除/填充/变换/保留)。
- 风险等级:将特征按质量分为 A(可直接使用)、B(需处理)、C(建议剔除)三级。
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 检验应纳入日常监控体系。
- 数据质量报告是数据探查的标准化输出,需包含问题定位、处理建议和风险等级,便于跨团队协作。