4. 数据准备与探索:数据质量检查、缺失值处理、异常值检测、特征分布分析
在金融风控模型开发中,数据准备与探索(Data Preparation & Exploration, DPE)是决定模型上限的关键环节。业界有句共识:“垃圾进,垃圾出”。本章将系统讲解数据质量检查、缺失值处理、异常值检测与特征分布分析四大核心步骤,确保后续建模与A/B分流实验建立在干净、可靠的数据基础上。
4.1 数据质量检查
数据质量检查是DPE的第一步,主要从完整性、准确性、一致性、时效性四个维度展开。金融风控数据通常包含用户基本信息、交易流水、征信记录、设备指纹等异构数据源,质量检查需覆盖以下清单:
| 检查维度 | 检查项 | 典型问题 | 检查方法 |
|---|---|---|---|
| 完整性 | 缺失率、空值、空字符串 | 收入字段缺失率 > 50% | df.isnull().sum() / len(df) |
| 准确性 | 值域、格式、逻辑校验 | 年龄 < 0 或 > 120 | describe() + 业务规则 |
| 一致性 | 跨表主键、枚举值映射 | 性别字段同时存在 'M'/'男'/'1' | value_counts() + 字典映射 |
| 时效性 | 时间戳范围、数据延迟 | 申请日期晚于当前日期 | min/max + 业务容忍窗口 |
实战建议:在风控场景中,建议为每个字段建立数据质量监控看板,每日自动扫描缺失率、异常值比例、分布漂移等指标,并设置告警阈值(如缺失率突增 > 5% 时触发人工核查)。
4.2 缺失值处理
缺失值处理需区分随机缺失(MAR)、完全随机缺失(MCAR)和非随机缺失(MNAR)三种机制。金融数据中,收入、负债等敏感字段常呈现MNAR特征,直接删除或简单填充可能引入偏差。常用处理方法如下:
- 删除法:适用于缺失率 < 5% 且为MCAR的字段。行删除(listwise deletion)或列删除(drop column)。
- 统计填充:均值/中位数/众数填充。适用于数值型低缺失率字段,但会降低方差。
- 模型预测填充:使用KNN、随机森林或XGBoost预测缺失值。精度高,但计算成本大。
- 业务规则填充:如“收入缺失”用“公积金基数×系数”推算,保留业务可解释性。
- 缺失指示变量:新增二值特征 is_missing,保留缺失模式信息,尤其适合MNAR场景。
风控特殊处理:对于“逾期天数”、“负债率”等强预测力字段,若缺失率 > 30%,建议先分析缺失模式是否与坏样本相关。若坏样本中该字段缺失率显著更高,则缺失本身即构成强信号,应保留缺失指示变量。
4.3 异常值检测
异常值在风控中可能代表欺诈、数据录入错误或极端信用行为。检测方法需结合业务理解与统计手段:
| 方法 | 适用场景 | 阈值/参数 | 金融案例 |
|---|---|---|---|
| Z-Score | 近似正态分布 | |Z| > 3 | 交易金额偏离均值3σ以上 |
| IQR(四分位距) | 偏态分布 | Q1 - 1.5×IQR 或 Q3 + 1.5×IQR | 年龄字段的极端值 |
| 孤立森林 | 高维、非线性 | 异常分数 > 0.6 | 设备指纹异常检测 |
| DBSCAN | 密度聚类 | eps=0.5, min_samples=10 | 团伙欺诈识别 |
注意:不要机械删除所有异常值。在风控中,某些异常值(如单笔大额转账、深夜登录)可能是欺诈的强特征。建议先标记异常,再结合业务标签(是否逾期/欺诈)分析其预测能力,决定保留、截尾或单独建模。
4.4 特征分布分析
特征分布分析帮助理解数据形态、识别长尾分布、发现潜在的数据泄露或样本偏差。常用分析手段包括:
- 单变量分布:直方图、核密度估计(KDE)、箱线图。关注偏度、峰度、多峰性。
- 双变量关系:散点图、分组箱线图、相关性热力图。识别线性/非线性关系。
- 分组对比:好样本 vs 坏样本的分布差异。使用KS检验、PSI(群体稳定性指标)量化。
- 时间稳定性:按时间窗口(周/月)绘制特征分布,检测概念漂移。
风控关键指标:PSI < 0.1 表示特征稳定;0.1~0.25 需关注;> 0.25 表示严重漂移,需重新训练或调整模型。IV(信息量)用于衡量特征区分度:IV < 0.02 为弱特征,0.02~0.1 为中等,> 0.1 为强特征。
4.5 实战代码示例:数据质量检查与缺失值处理
以下代码展示使用Python进行数据质量检查与缺失值处理的典型流程:
import pandas as pd
import numpy as np
# 加载数据
df = pd.read_csv('credit_data.csv')
# 1. 数据质量检查
print("=== 数据概览 ===")
print(df.info())
print("\n=== 缺失率统计 ===")
missing_rate = df.isnull().mean().sort_values(ascending=False)
print(missing_rate[missing_rate > 0])
# 2. 异常值检测(IQR法)
def detect_outliers_iqr(series):
Q1 = series.quantile(0.25)
Q3 = series.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
return (series < lower) | (series > upper)
# 对数值型字段检测异常
num_cols = df.select_dtypes(include=[np.number]).columns
outlier_mask = pd.DataFrame()
for col in num_cols:
outlier_mask[col] = detect_outliers_iqr(df[col])
print("\n=== 各字段异常值数量 ===")
print(outlier_mask.sum())
# 3. 缺失值处理
# 低缺失率字段:中位数填充
for col in ['income', 'age']:
if df[col].isnull().mean() < 0.05:
df[col].fillna(df[col].median(), inplace=True)
# 高缺失率字段:新增缺失指示变量 + 业务规则填充
if df['debt_ratio'].isnull().mean() > 0.3:
df['debt_ratio_missing'] = df['debt_ratio'].isnull().astype(int)
# 业务规则:用收入估算
df['debt_ratio'].fillna(df['income'] * 0.3, inplace=True)
print("\n=== 处理完成 ===")
print(df.isnull().sum().sum(), "个缺失值剩余")
生产环境建议:将上述流程封装为数据质量管道,使用DVC(数据版本控制)管理数据快照,确保每次模型训练使用的数据版本可追溯。同时,将质量检查结果写入日志系统,便于后续审计与复盘。