3. 数据采集与清洗:数据源梳理、缺失值处理、异常值检测与处理
在支付风控建模中,数据质量直接决定模型效果的上限。本章聚焦于从原始数据到可用样本的转化过程,涵盖数据源梳理、缺失值处理以及异常值检测与处理三大核心环节。通过系统化的清洗策略,确保后续分群与评分模型建立在可靠的数据基础之上。
3.1 数据源梳理与分类
支付风控数据通常来源于多个异构系统,梳理数据源是清洗的第一步。根据数据产生主体与用途,可将数据源分为以下三类:
| 数据类别 | 典型数据源 | 关键字段示例 | 采集频率 |
|---|---|---|---|
| 交易数据 | 支付网关、收单系统 | 交易金额、时间、商户ID、支付方式 | 实时/准实时 |
| 用户数据 | 用户中心、KYC系统 | 注册时间、实名等级、绑定手机、设备指纹 | 每日增量 |
| 行为数据 | 埋点日志、风控事件库 | 登录IP、操作序列、历史拒付次数 | 实时流式 |
实践要点: 数据源梳理阶段应输出一份《数据字典》,明确每个字段的业务含义、数据类型、取值范围及缺失率基线,作为后续清洗与特征工程的统一参考。
3.2 缺失值处理策略
缺失值在风控数据中普遍存在,处理不当会导致模型偏差或信息损失。根据缺失机制与业务含义,采用分层处理策略:
- 缺失机制判断: 区分完全随机缺失(MCAR)、随机缺失(MAR)与非随机缺失(MNAR)。支付风控中,设备指纹字段常为MAR,而高风险交易的部分字段可能为MNAR。
- 高缺失率字段处理: 缺失率超过70%的字段,优先考虑删除;若业务认为重要,可保留并作为“是否缺失”的二元特征。
- 中低缺失率字段填充:
- 数值型:使用中位数填充(抗异常值),或按分群组内均值填充。
- 类别型:使用众数填充,或单独编码为“未知”类别。
- 时序型:使用前向填充(ffill)或线性插值。
- 模型预测填充: 对于关键字段(如用户收入等级),可使用随机森林或KNN预测缺失值,但需注意避免数据泄露。
避坑提醒: 在分群评分场景中,缺失值填充应在分群操作之前完成,且填充参数(如中位数)必须基于训练集计算,再应用到验证集与测试集,防止未来信息泄露。
3.3 异常值检测与处理
支付数据中的异常值可能源于欺诈行为、系统故障或录入错误。异常值检测需结合统计方法与业务规则,避免误杀正常交易。
3.3.1 常用检测方法对比
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Z-Score | 近似正态分布 | 计算简单,阈值明确 | 对非正态分布效果差 |
| IQR(四分位距) | 偏态分布 | 不受极端值影响 | 无法区分业务异常 |
| 孤立森林 | 高维数据 | 线性时间复杂度 | 对局部异常不敏感 |
| 业务规则 | 强约束场景 | 可解释性强 | 规则维护成本高 |
3.3.2 处理策略
- 截尾处理(Winsorization): 将超出阈值(如99.9%分位数)的数值替换为阈值本身,保留样本量同时抑制极端值影响。
- 删除: 仅当异常值明确由系统故障或录入错误导致,且占比低于1%时,考虑删除。
- 分箱处理: 将连续变量离散化,如将交易金额分为“小额/中额/大额/超大额”,降低异常值对模型的直接冲击。
- 标记为特征: 保留异常值,并新增“是否异常”的二元特征,让模型自行学习异常模式。
风控特殊注意: 欺诈交易本身属于“异常值”,但却是模型需要识别的目标。因此,在异常值处理时,切勿将欺诈样本直接删除或截尾,而应结合标签信息进行差异化处理:对正常样本做清洗,对欺诈样本保留原始形态。
3.4 数据清洗流程总览
以下SVG图展示了从原始数据到清洗后样本的完整流程,包含数据源接入、缺失值处理、异常值检测与处理三个主要阶段,以及各阶段的关键输出物。
3.5 代码示例:缺失值与异常值处理
以下Python代码展示了在支付风控场景中,对交易金额字段进行缺失值填充与异常值检测的典型实现:
import pandas as pd
import numpy as np
# 示例数据:交易金额(单位:元)
df = pd.DataFrame({
'transaction_id': range(1, 101),
'amount': [200, 150, np.nan, 300, 50, 10000, 180, np.nan, 250, 120] * 10
})
# 1. 缺失值处理:使用中位数填充
median_amount = df['amount'].median()
df['amount_filled'] = df['amount'].fillna(median_amount)
# 2. 异常值检测:IQR方法
Q1 = df['amount_filled'].quantile(0.25)
Q3 = df['amount_filled'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 标记异常值(不删除,仅标记)
df['is_outlier'] = ((df['amount_filled'] < lower_bound) |
(df['amount_filled'] > upper_bound)).astype(int)
# 3. 截尾处理:将异常值替换为上下限
df['amount_winsorized'] = df['amount_filled'].clip(lower=lower_bound, upper=upper_bound)
print(f"中位数填充值: {median_amount}")
print(f"异常值数量: {df['is_outlier'].sum()}")
print(f"截尾后金额范围: [{lower_bound:.2f}, {upper_bound:.2f}]")
输出说明: 上述代码中,缺失值使用中位数填充,异常值通过IQR方法检测并标记,最后对异常值进行截尾处理。在实际风控项目中,建议将清洗参数(如中位数、分位数阈值)持久化保存,以便在模型上线时对实时数据应用相同的清洗逻辑。
3.6 本章小结
数据采集与清洗是支付风控建模的基石。通过系统化的数据源梳理、分层缺失值处理以及多维度异常值检测,能够显著提升样本质量,为后续的分群分析与评分卡开发提供可靠的数据保障。建议在每次清洗后,输出完整的清洗日志,记录缺失率变化、异常值处理比例及关键参数,便于模型迭代与审计追溯。