4. 数据探索性分析(EDA)复盘归纳总结

数据探索性分析,简称 EDA。
说白了,就是项目拿到数据后,正式建模前,你需要先跟数据“混个脸熟”。
我个人习惯把 EDA 叫作“数据体检”。你不做体检就敢上手术台?胆子也太大了。

在 MD 特征学习项目里,EDA 复盘的目的很明确:
确认跑进来的数据质量没问题,分布合理,特征之间的关联度在我们预期内。
如果有坑,得在 EDA 阶段就填上,千万别留到训练环节再炸。

4.1 EDA 复盘的核心流程

我总结了 EDA 复盘的四个步骤,基本覆盖了项目中的常见场景。

  1. 数据质量检查——缺失值、重复行、数据类型对不对
  2. 单变量分布分析——均值、方差、偏度、峰度,看看数据长什么样
  3. 双变量/多变量关系分析——相关性、交叉表、分组统计
  4. 异常值与边界检测——离群点、极端值、不合理区间

嗯,复盘的时候,我们不只是跑一遍代码就完事。
要回头问自己:当初 EDA 阶段漏掉什么了吗?有没有哪个坑,是后来才发现的?

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 连续 均值/中位数对比
复盘关键点:如果发现特征之间相关系数超过 0.8,就要看要不要做特征筛选或降维。
我经历的项目中,有两次因为没处理高相关特征,导致模型过拟合严重。
后来在 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,你到底要产出什么?

我个人习惯把产出物分成三块:

  1. EDA 复盘报告——包含数据质量清单、分布结果、相关矩阵、异常值分析
  2. 修复清单——明确标记哪些问题已经修了,哪些还需要跟进
  3. 更新后的特征工件——比如清洗后的数据文件、特征描述文档

这三样东西,在项目交接、迭代回退、问题排查时,都是救命稻草。

建议:把 EDA 脚本和报告做成可复用的模板。
下次有新项目,直接套模板跑一遍,能节省至少 50% 的时间。
我在团队里就是这么干的,效果很好。

4.7 复盘检查清单

最后给你一份我在项目中用的复检清单。每次 EDA 复盘完,挨个打勾:

# 检查项 状态
1 缺失值检查与处理 ☐
2 重复行去重验证 ☐
3 数据类型确认无误 ☐
4 单变量分布分析完成 ☐
5 多变量相关性分析完成 ☐
6 异常值检测与标注 ☐
7 EDA 报告更新到项目文档 ☐
8 修复清单同步给团队 ☐

这份清单我每轮迭代都会用。你如果不放心,也可以复制一份贴在你的项目里。

嗯,EDA 复盘就讲到这里。下一件事才是真正的重头戏——不过那得等你把数据搞干净了再说。