第四章:探索性数据分析(EDA)与数据质量报告生成
数据拿到手,别急着建模。我见过太多团队,上来就调参跑模型,结果跑出来的分数根本不敢用。为什么?因为数据里藏着什么问题,你根本不知道。EDA这步,说白了就是给你的数据做个全面体检。不做体检就上手术台,风险太大。
我个人习惯,先花至少一天时间做EDA。别觉得浪费时间——数据质量报告出来以后,你后面的工作会顺畅得多。这一章,我就带着你走一遍EDA的核心流程,顺便说说我踩过的坑。
4.1 EDA到底要干什么?
信用评分模型里,EDA的目标很明确:
- 看懂每个字段的分布形态
- 发现缺失值、异常值、重复值
- 检查变量的逻辑合理性(比如年龄不能是负数)
- 初步判断变量和违约率的关系
- 为数据清洗和特征工程提供依据
嗯,说白了就是三件事:看分布、找脏数据、摸关系。
4.2 单变量分析——先摸清每个字段的底细
单变量分析是最基础的。我会把字段分成两类:数值型和分类型。处理方式不一样。
4.2.1 数值型字段
我会先看五个统计量:最小值、最大值、均值、中位数、标准差。然后画直方图或箱线图。特别关注:
- 是否有极端值(比如收入字段出现1亿)
- 分布是否严重偏态(信用分字段通常偏左,正常)
- 是否有不合理取值(比如年龄大于120)
举个例子,你想想看:收入字段如果均值是5000,中位数是3000,说明大部分人收入偏低,但少数高收入拉高了均值。这种偏态分布,后面做分箱或WOE转换时得格外小心。
4.2.2 分类型字段
对于性别、婚姻状况、学历这类离散字段,我会看频数和占比。主要检查:
- 类别数量是否过多(比如城市字段有3000个值,那得考虑合并)
- 是否有低占比类别(占比低于1%的,可以考虑归为"其他")
- 是否有逻辑矛盾(比如"性别"字段出现"未知",而"婚姻状况"字段出现"已婚且有配偶")
我记得有一次,一个信用卡申请数据集里,"居住状态"字段有"自有"、"租住"、"集体宿舍",还有一个"其他"占比不到0.5%。建模时如果不处理,这个类别在训练集和测试集里可能会分布不一致,导致模型不稳定。
4.3 双变量分析——看变量和违约的关系
单变量看完了,接下来要看每个变量和目标变量(是否违约)的关系。这才是EDA的核心。
对于数值型变量,我会分违约组和正常组,画两个箱线图对比。如果两组的中位数差异明显,这个变量大概率有价值。
对于分类型变量,我会计算每个类别下的违约率,然后画柱状图。比如"学历"字段:如果"硕士及以上"违约率只有2%,而"高中以下"违约率是8%,这就是个强区分变量。
| 学历类别 | 样本数 | 违约样本数 | 违约率 |
|---|---|---|---|
| 硕士及以上 | 5,000 | 100 | 2.0% |
| 本科 | 12,000 | 480 | 4.0% |
| 大专 | 8,000 | 560 | 7.0% |
| 高中及以下 | 5,000 | 400 | 8.0% |
你看这个表,违约率从2%到8%,梯度非常清晰。这种变量在信用评分模型里就是"好变量"。反过来,如果某个变量的各类别违约率差不多(比如都在5%左右),那它对模型帮助不大。
4.4 缺失值分析——别漏掉任何一块拼图
缺失值处理不当,模型会学出奇怪的东西。我一般会做两步:
- 统计每个字段的缺失率
- 分析缺失模式——是随机缺失,还是和某个字段有关?
举个例子,某数据集中"工作年限"字段缺失率达到30%,但"收入"字段完整。那么缺失的工作年限可能是随机缺失,可以用中位数填补。但如果是"学历"缺失,而"收入"也偏低,那缺失可能并非随机——这时候直接填中位数会引入偏差。
4.5 数据质量报告——把发现变成文档
EDA做完了,不能只留在脑子里。必须生成一份数据质量报告,让团队每个人都看得懂。我习惯用Python的pandas-profiling(现在叫ydata-profiling)自动生成报告,但也会手动补充关键发现。
报告里应该包含哪些内容呢?下面是清单:
- 总体数据概况:行数、列数、内存占用
- 缺失值汇总:字段名、缺失数量、缺失率
- 异常值列表:哪些字段有极端值,处理建议
- 重复行统计:重复样本数和处理方式
- 变量分布描述:对重点字段给出分布特征
- 变量与目标的相关性:初步筛选变量
- 数据质量问题与行动项:比如"字段A需要联系业务方确认逻辑"
下面是一个简化的Python代码示范:
import pandas as pd
import numpy as np
# 读取数据
df = pd.read_csv('credit_data.csv')
# 缺失值统计
missing = df.isnull().sum()
missing_rate = missing / len(df)
missing_df = pd.DataFrame({'字段': df.columns, '缺失数': missing, '缺失率': missing_rate})
# 异常值检测(以年龄为例,假设合理范围18-80)
outliers = df[(df['age'] < 18) | (df['age'] > 80)]
print(f'年龄异常值数量: {len(outliers)}')
# 重复行检测
duplicates = df.duplicated().sum()
print(f'重复行数: {duplicates}')
# 生成简要报告
report = {
'总样本数': len(df),
'总字段数': len(df.columns),
'缺失字段数': (missing > 0).sum(),
'重复行数': duplicates,
'内存占用(MB)': df.memory_usage(deep=True).sum() / 1024**2
}
print(report)
4.6 数据质量报告生成流程(一张图说清)
上面的步骤有些多,我给总结成一张流程图。你看一眼就明白整个EDA和报告生成的路径:
4.7 注意事项:别让EDA变成走过场
最后,说几条我这些年总结的教训:
- 不要只看汇总统计量——平均数有时会骗人,一定要画图看分布。我遇到过均值正常但实际分布有双峰的案例。
- 注意时间维度——信用数据通常有时间戳。如果训练集和测试集的时间分布不一致,模型会失效。我曾经因此重做过整个项目。
- 记录每一个发现——哪怕你觉得"这个异常值可能是数据录入错误",也要写进报告。后续沟通时你会有据可查。
- 控制报告篇幅——太详细没人看,太粗略又没用。我一般把详细统计放在附录,正文只呈现关键发现和行动项。
EDA做扎实了,后面的数据清洗、特征工程、建模都会非常顺畅。嗯,这一章就这么多。动手把这套流程跑一遍,你很快就会有自己的感觉。数据不会骗人,但前提是你得懂得怎么看它。