4. 数据探索性分析(EDA)复盘归纳总结
数据探索性分析,简称 EDA。
说白了,就是项目拿到数据后,正式建模前,你需要先跟数据“混个脸熟”。
我个人习惯把 EDA 叫作“数据体检”。你不做体检就敢上手术台?胆子也太大了。
在 MD 特征学习项目里,EDA 复盘的目的很明确:
确认跑进来的数据质量没问题,分布合理,特征之间的关联度在我们预期内。
如果有坑,得在 EDA 阶段就填上,千万别留到训练环节再炸。
4.1 EDA 复盘的核心流程
我总结了 EDA 复盘的四个步骤,基本覆盖了项目中的常见场景。
- 数据质量检查——缺失值、重复行、数据类型对不对
- 单变量分布分析——均值、方差、偏度、峰度,看看数据长什么样
- 双变量/多变量关系分析——相关性、交叉表、分组统计
- 异常值与边界检测——离群点、极端值、不合理区间
嗯,复盘的时候,我们不只是跑一遍代码就完事。
要回头问自己:当初 EDA 阶段漏掉什么了吗?有没有哪个坑,是后来才发现的?
你想想看,如果下一个迭代换了个工程师来接手项目,你的 EDA 日志能让他半小时内搞清楚数据全貌吗?
4.2 数据质量检查——别让脏数据骗了你
数据质量是 EDA 的起点。
我见过太多项目,模型怎么调都不收敛,最后排查才发现——输入数据里有 30% 是空值,或者类型标错了。
复盘时,你需要回顾这些检查点:
| 检查项 | 工具/方法 | 复盘重点 |
|---|---|---|
| 缺失值比例 | df.isnull().sum() |
缺失超过 5% 就要评估要不要补 |
| 重复行 | df.duplicated().sum() |
重复数据会放大特征权重 |
| 数据类型 | df.dtypes |
数值列有没有误标成 object |
| 值域范围 | df.describe() |
最小值/最大值是否合理 |
我曾经在一个项目里,发现某列“年龄”数据出现了负数。
你猜怎么着?采集端把默认值填成了 -1。
这种问题,EDA 阶段如果不排查,训练时模型会莫名其妙学到“负年龄”这种鬼特征。
复盘时该怎么做?
- 把当初 EDA 脚本里的质量检查部分重新跑一遍
- 看日志里有没有之前忽略的警告
- 如果发现了新的脏数据,立刻修复并记录
项目迭代中,数据源可能会变。每次新增数据,都要重新跑质量检查。
别偷懒,偷懒会付出代价。
4.3 单变量分布分析——摸清每个特征的脾气
单个特征的分布,直接决定了后面怎么选模型、怎么调参。
比如特征如果严重偏态,你可能需要做对数变换或 Box-Cox 变换。
复盘时我会重点看这几个指标:
- 均值与中位数对比——差距大说明有偏态
- 标准差——方差太大要考虑标准化
- 偏度与峰度——超出 [-2, 2] 就算异常
- 分类特征的取值频次——有没有长尾分布
举个例子,在 MD 特征学习里,我们常遇到“特征频率”这个字段:
# 分布检查示例
import pandas as pd
import numpy as np
df = pd.read_csv('md_features.csv')
desc = df['feature_frequency'].describe()
print(desc)
# 偏度计算
skewness = df['feature_frequency'].skew()
print(f'偏度: {skewness:.2f}')
# 可视化要点
# 直方图 + 核密度估计曲线,确认分布形态
我建议你在复盘时,把每个特征的历史分布图和当前分布图放在一起对比。
如果分布变了,说明数据源可能发生了变化。这件事不搞清楚,后面的建模都是白搭。
4.4 多变量关系分析——发现隐藏的关联
单变量看完了,就得看特征之间怎么互相影响。
你想想看,两个特征高度相关的时候,模型就可能学到冗余信息。
复盘阶段我常用的方法:
| 方法 | 适用场景 | 输出形式 |
|---|---|---|
| 皮尔逊相关系数 | 两个连续特征 | 数值矩阵 |
| Spearman 秩相关 | 有序分类 + 连续 | 数值矩阵 |
| 交叉表 | 两个分类特征 | 频次表格 |
| 分组统计 | 分类 vs 连续 | 均值/中位数对比 |
我经历的项目中,有两次因为没处理高相关特征,导致模型过拟合严重。
后来在 EDA 阶段就做了相关性分析,问题迎刃而解。
4.5 异常值与边界检测——别被离群点带偏
异常值这件事,我一直觉得“既要重视,又别过度”。
为什么这么说?因为有些异常值是噪声,有些是真实信号。
在 MD 特征学习项目里,我遇到过这样的情况:某个特征的取值在 0-100 之间,但突然多了个 9999。查了之后发现是采集设备故障,这种就要果断剔除。
常用的检测方法:
- Z-score 法:超过 3 个标准差算异常
- IQR 法:低于 Q1-1.5*IQR 或高于 Q3+1.5*IQR 算异常
- 箱线图:直观查看离群点
代码示例:
def detect_outliers_iqr(data, column):
Q1 = data[column].quantile(0.25)
Q3 = data[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = data[(data[column] < lower_bound) |
(data[column] > upper_bound)]
return outliers
outliers_df = detect_outliers_iqr(df, 'feature_value')
print(f'发现 {len(outliers_df)} 条异常记录')
后来发现,那些异常值其实是某个特定业务场景下的正常数据。
结果模型在那个场景下预测效果极差。
所以千万不要机械地剔除异常值,要结合业务逻辑来判断。
4.6 EDA 复盘的产出物
折腾半天,复盘完 EDA,你到底要产出什么?
我个人习惯把产出物分成三块:
- EDA 复盘报告——包含数据质量清单、分布结果、相关矩阵、异常值分析
- 修复清单——明确标记哪些问题已经修了,哪些还需要跟进
- 更新后的特征工件——比如清洗后的数据文件、特征描述文档
这三样东西,在项目交接、迭代回退、问题排查时,都是救命稻草。
下次有新项目,直接套模板跑一遍,能节省至少 50% 的时间。
我在团队里就是这么干的,效果很好。
4.7 复盘检查清单
最后给你一份我在项目中用的复检清单。每次 EDA 复盘完,挨个打勾:
| # | 检查项 | 状态 |
|---|---|---|
| 1 | 缺失值检查与处理 | ☐ |
| 2 | 重复行去重验证 | ☐ |
| 3 | 数据类型确认无误 | ☐ |
| 4 | 单变量分布分析完成 | ☐ |
| 5 | 多变量相关性分析完成 | ☐ |
| 6 | 异常值检测与标注 | ☐ |
| 7 | EDA 报告更新到项目文档 | ☐ |
| 8 | 修复清单同步给团队 | ☐ |
这份清单我每轮迭代都会用。你如果不放心,也可以复制一份贴在你的项目里。
嗯,EDA 复盘就讲到这里。下一件事才是真正的重头戏——不过那得等你把数据搞干净了再说。