第三章 数据采集与清洗:数据源类型、数据质量评估、常见数据清洗方法
做风控的朋友都知道一句话:垃圾进,垃圾出。模型再牛,数据不行,全白搭。
我刚开始做量化风控那会儿,接过一个信贷项目。当时业务方拍着胸脯说数据质量没问题,结果我一跑分布,好家伙,某个字段的缺失率高达 40%。嗯,从那以后,我养成了一个习惯——先看数据,再谈模型。
这一章,我们就聊聊数据采集与清洗。说白了,就是搞清楚三件事:数据从哪来、数据好不好、数据怎么洗。
核心观点:数据清洗不是体力活,是风控的第一道防线。你花 80% 的时间做清洗,剩下 20% 的时间建模,这很正常。
3.1 数据源类型:你的数据从哪来?
风控数据源,我习惯分成三大类。每一类都有它的脾气。
| 数据源类型 | 典型来源 | 特点 | 常见问题 |
|---|---|---|---|
| 内部业务数据 | 用户注册信息、交易流水、还款记录 | 高可信度、强关联性 | 字段缺失、历史数据格式不统一 |
| 外部征信数据 | 央行征信、百行征信、同盾等 | 覆盖面广、权威性强 | 更新延迟、接口不稳定 |
| 行为与设备数据 | 埋点数据、设备指纹、IP 归属地 | 实时性强、维度丰富 | 噪声大、隐私合规风险 |
我个人经验是:内部数据是地基,外部数据是砖瓦,行为数据是装修。地基不稳,后面全得塌。
小技巧:做数据采集时,建议先列一个「数据源清单」,标注每个字段的获取频率、更新周期、接口负责人。我在项目中吃过亏——某个外部征信接口突然挂了,模型跑出来全是空值,排查了整整一天。
3.2 数据质量评估:怎么判断数据能不能用?
数据拿到手,别急着建模。先做一轮质量评估。我一般看四个维度:
- 完整性:字段缺失率有多高?超过 30% 的字段,我建议直接放弃。
- 准确性:数据值是否合理?比如年龄字段出现 200 岁,这明显是脏数据。
- 一致性:同一字段在不同表中是否矛盾?比如用户 A 在表 1 中是男性,在表 2 中是女性。
- 时效性:数据是否过期?风控场景下,3 个月前的征信报告基本没有参考价值。
你想想看,如果完整性只有 60%,你强行建模,结果会怎样?模型会学偏,线上跑起来全是误杀或漏杀。
避坑指南:我曾经接手过一个项目,业务方说数据质量很好。我随手抽了 1000 条样本,发现「婚姻状况」字段里居然有「已婚」「未婚」「离异」「丧偶」「未知」五种取值,但「未知」占了 40%。这其实不是缺失,是业务方偷懒没填。嗯,这种坑,一定要在评估阶段揪出来。
3.3 常见数据清洗方法:缺失值、异常值、重复值
清洗方法很多,但核心就三类:缺失值、异常值、重复值。我们一个一个说。
3.3.1 缺失值处理
缺失值是最常见的。处理方法取决于缺失率:
- 缺失率 < 5%:直接删除该行,或者用均值/中位数填充。我个人习惯用中位数,因为它不受极端值影响。
- 缺失率 5% - 20%:用模型预测填充(比如 KNN、随机森林),或者用业务规则填充。比如「收入」字段缺失,可以用「职业+地区」的平均收入来补。
- 缺失率 > 20%:建议删除该字段。强行填充只会引入噪声。
# 示例:用中位数填充缺失值
import pandas as pd
df = pd.read_csv('credit_data.csv')
# 检查缺失率
missing_rate = df.isnull().mean()
print(missing_rate)
# 对缺失率低于 5% 的字段,用中位数填充
for col in missing_rate[missing_rate < 0.05].index:
df[col].fillna(df[col].median(), inplace=True)
个人经验:千万别用「0」去填充缺失值,除非你明确知道这个字段的 0 有业务含义。我见过有人把「年龄」缺失填成 0,结果模型把 0 岁用户识别为高风险——这完全是个乌龙。
3.3.2 异常值处理
异常值,说白了就是那些「离谱」的数据。怎么判断?常用方法有:
- 3σ 原则:数据服从正态分布时,超过均值 ±3 倍标准差的值视为异常。
- 箱线图法:超过 Q1 - 1.5*IQR 或 Q3 + 1.5*IQR 的值视为异常。
- 业务规则:比如「月收入」不可能超过 1000 万,除非是上市公司老板。
处理方式:
- 如果是录入错误,直接修正或删除。
- 如果是真实但极端的值(比如大额交易),可以考虑做截尾处理(winsorization)。
# 示例:用箱线图法检测异常值
Q1 = df['income'].quantile(0.25)
Q3 = df['income'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 标记异常值
df['income_anomaly'] = (df['income'] < lower_bound) | (df['income'] > upper_bound)
避坑指南:我曾经处理过一个反欺诈项目,发现某个用户的「交易金额」异常高,按箱线图法应该删除。但后来一查,这个用户是正常的大客户。所以,异常值不一定是错误值,一定要结合业务判断。
3.3.3 重复值处理
重复值看起来简单,但坑也不少。
- 完全重复:所有字段都一样。直接删除,保留一条即可。
- 部分重复:比如同一个用户 ID 出现多次,但其他字段不同。这时候需要判断是数据冗余还是业务逻辑(比如多次申请)。
# 示例:删除完全重复的行
df.drop_duplicates(inplace=True)
# 检查部分重复:按用户 ID 去重,保留最新的一条
df.sort_values('apply_date', ascending=False, inplace=True)
df.drop_duplicates(subset='user_id', keep='first', inplace=True)
小技巧:处理重复值时,建议先做一次「重复值分析」,看看重复率有多高。如果重复率超过 10%,说明数据采集环节有问题,需要跟业务方沟通。
3.4 本章知识体系图
下面这张图,帮你把本章的核心逻辑串起来:
这张图你看懂了吗?数据源是起点,质量评估是关卡,清洗方法是工具。三者缺一不可。
总结一句话:数据清洗不是一次性工作,而是贯穿整个风控体系的生命周期。每次模型迭代,都要重新审视数据质量。我见过太多团队,模型上线后就不管数据了,结果半年后模型效果直线下降——嗯,这就是典型的「数据债」。
公众号:蓝海资料掘金营,微信deep3321