【数据预处理】EDA详解
一、一句话定义
EDA = 探索性数据分析,是建模 / 数据清洗之前的诊断步骤:不预设模型、不做预测,只用图表、统计指标把数据集全貌、问题、规律全部挖出来,指导后续数据预处理、清洗、特征工程。你可以理解成:给数据做一次全面体检。
二、EDA 核心目标(为什么预处理前必须做 EDA)
-
看懂数据:每列含义、数据类型、取值范围;
-
定位脏数据:缺失值、异常值、重复数据、错误编码;
-
识别分布:数值是否正态、是否偏斜、有无长尾;
-
分析关系:特征与标签相关性、特征间多重共线性;
-
发现业务规律:分组差异、潜在分层;
-
指导后续处理方案(最重要)
- 缺失值:该删除、均值填充、中位数填充还是模型填充?
- 异常值:直接剔除、缩尾处理、对数转换?
- 偏态数据:是否需要 log 标准化?
- 强相关特征:是否要删除冗余特征?
三、EDA 完整 4 大模块(预处理诊断标准流程)
模块 1:基础概况检查(宏观)
读取数据后第一步,快速掌握数据集基本信息
- 样本量、特征数量、标签列;
- 字段类型:数值型 (int/float)、类别型 (object/category)、时间型;
- 基础统计:count、mean、std、min、四分位数、max(describe);
- 重复行数量、完全重复样本;
- 字段唯一值数量(区分高基数 / 低基数分类特征)。
输出结论示例:数据集共 10000 行,12 特征;3 个分类字段、9 个数值字段;存在 230 条重复样本。
模块 2:缺失值诊断(清洗第一重点)
统计每列缺失比例、缺失分布:
- 各字段缺失数量、缺失占比;
- 缺失是否存在关联(比如 A 字段缺失时 B 也缺失,是业务逻辑导致);
- 可视化热力图展示缺失分布。
指导清洗:
- 缺失率 > 70%:直接删除该列;
- 低缺失连续特征:中位数填充(抗异常);
- 分类特征:众数填充 / 新增 “未知” 类别;
- 缺失有业务含义:新增 Is_Missing 标记特征。
模块 3:单变量分析(单列分布、异常检测)
分别对数值特征、分类特征单独分析
1)数值型特征
- 图表:直方图、箱线图;
- 重点观察:
① 分布:正态 / 左偏 / 右偏、长尾;② 异常值:箱线图离群点、远超合理业务区间的值;③ 取值范围是否符合常识(如年龄 = 200、收入 =-1000)。
2)分类特征
- 图表:计数柱状图、饼图;
- 重点观察:类别不平衡、稀有小类别、错误文本编码。
指导预处理:
- 右偏严重:log 变换、Box-Cox 转换;
- 大量极端异常:截断 / 缩尾;
- 稀有类别合并为 other。
模块 4:多变量关系分析(特征 - 特征、特征 - 标签)
-
相关性分析(数值)
- 皮尔逊相关系数热力图;
- 识别多重共线性(两个特征高度相关,后续需降维 / 删特征);
-
特征 vs 目标标签(建模关键)
- 分类任务:箱线图、分组柱状图,看不同类别下目标分布差异;
- 回归任务:散点图,观察线性 / 非线性关系;
-
交叉分组:多特征组合,挖掘隐藏分层规律。
指导特征工程:
- 和标签几乎无关的弱相关特征可剔除;
- 高度共线性二选一删除;
- 非线性关系特征:新增多项式特征、分箱特征。
四、EDA 与「数据预处理」的先后关系
- EDA(探索诊断)→ 2. 数据清洗预处理 → 3. 特征工程 → 4. 建模
- 不做 EDA 直接清洗:盲目操作,比如随便均值填充、乱删异常值,会丢失关键业务信息;
- EDA 是诊断,预处理是对症下药。
五、EDA 常用工具代码(Python pandas/matplotlib/seaborn)
1. 基础统计:均值、方差、最值、分位数、样本量
需要获取的指标
- 全局:总样本量、总字段数
- 数值字段:count有效样本、mean均值、std方差、min最小值、max最大值、25%/50%/75%四分位数
- 类别字段:唯一值数量、频次topN、占比
获取方法(Python)
import pandas as pd
df = pd.read_csv("data.csv")
# 1. 样本、字段总量
print(f"总样本数:{df.shape[0]}, 总特征数:{df.shape[1]}")
# 2. 数值型基础统计(均值/方差/最值/分位数一键输出)
print(df.describe())
# 3. 类别型统计:唯一值、频次
for col in df.select_dtypes(include=["object", "category"]).columns:
print(f"\n字段 {col} 频次分布:")
print(df[col].value_counts(normalize=True).round(3))
2. 缺失值探查:缺失比例、缺失分布
需要获取指标
- 单字段缺失数量、缺失百分比
- 缺失联合分布:多字段是否同步缺失(如设备故障时多个传感器同时为空)
- 缺失分层分布:按标签/时间分组看缺失率差异
获取方法
# 1. 单字段缺失统计
missing_cnt = df.isnull().sum()
missing_ratio = (df.isnull().sum() / len(df)).round(4)
missing_df = pd.DataFrame({"缺失数量": missing_cnt, "缺失占比": missing_ratio})
print(missing_df[missing_df["缺失数量"] > 0])
# 2. 缺失组合分布(查看哪些行多字段同时缺失)
df[df.isnull().any(axis=1)].isnull().sum(axis=1).value_counts()
# 3. 分组缺失:按标签y看不同类别缺失率
df.groupby("label")["feature1"].apply(lambda x: x.isnull().mean())
3. 异常值探查:箱线图、3σ准则、IQR四分位法
需要获取内容
- IQR法:上下边界、落在边界外的异常样本数量、占比
- 3σ法:均值±3倍标准差,越界异常样本
- 可视化:箱线图直观展示离群点
核心公式
- IQR = Q75 - Q25
- 下界 = Q25 - 1.5*IQR
- 上界 = Q75 + 1.5*IQR
- 3σ区间:

获取方法
import seaborn as sns
import matplotlib.pyplot as plt
def detect_outlier(col_series):
# IQR检测
q1 = col_series.quantile(0.25)
q3 = col_series.quantile(0.75)
iqr = q3 - q1
lower = q1 - 1.5 * iqr
upper = q3 + 1.5 * iqr
iqr_outlier = ((col_series < lower) | (col_series > upper)).sum()
# 3σ检测
mu = col_series.mean()
std = col_series.std()
sigma_outlier = ((col_series < mu-3*std) | (col_series > mu+3*std)).sum()
return {"IQR异常数":iqr_outlier, "3σ异常数":sigma_outlier, "上下限":[lower, upper]}
# 遍历所有数值列
num_cols = df.select_dtypes(include=["int64","float64"]).columns
for col in num_cols:
res = detect_outlier(df[col])
print(f"{col}: {res}")
# 绘制箱线图
plt.figure()
sns.boxplot(y=df[col])
plt.title(f"{col} 箱线图")
plt.show()
4. 分布探查:特征直方图、标签分布、类别不平衡
需要获取内容
- 数值特征:直方图/核密度图,判断正态/右偏/左偏/双峰分布
- 分类标签:各类样本数量、占比,计算不平衡比例(最大类/最小类)
获取方法
# 1. 数值特征分布直方图
for col in num_cols:
plt.figure()
sns.histplot(df[col], kde=True)
plt.title(f"{col} 分布直方图")
plt.show()
# 2. 标签分布,判断类别不平衡
label_dist = df["label"].value_counts(normalize=True).round(3)
print("标签分布:\n", label_dist)
# 不平衡系数
imb_ratio = label_dist.max() / label_dist.min()
print(f"类别不平衡系数:{imb_ratio:.2f},大于4即严重不平衡")
5. 相关性分析:皮尔逊系数、热力图、多重共线性检测
需要获取内容
- 数值特征两两皮尔逊相关系数矩阵
- 相关性热力图可视化,标记|r|>0.7强相关特征对
- 多重共线性:VIF方差膨胀因子(VIF>10存在严重共线性)
获取方法
import statsmodels.stats.outliers_influence as oi
# 1. 皮尔逊相关系数
corr_matrix = df[num_cols].corr()
print(corr_matrix)
# 2. 热力图
plt.figure(figsize=(10,8))
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", vmin=-1, vmax=1)
plt.title("特征相关性热力图")
plt.show()
# 3. VIF多重共线性检测
X = df[num_cols].dropna()
vif_df = pd.DataFrame()
vif_df["特征名"] = X.columns
vif_df["VIF"] = [oi.variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
print(vif_df[vif_df["VIF"] > 10])
6. 数据类型校验:数值型、类别型、文本、时间特征
需要获取内容
- 每列原始dtype
- 人工区分四类:
- 数值型:int/float(连续、离散数值)
- 类别型:object/category(有限枚举值:性别、地区)
- 文本型:长字符串、无固定枚举(评论、摘要)
- 时间特征:datetime格式、可转为时间戳
获取方法
# 1. 打印全部字段原始类型
print(df.dtypes)
# 2. 自动筛选四类特征
num_cols = df.select_dtypes(include=["int64", "float64"]).columns.tolist()
cat_cols = df.select_dtypes(include=["object", "category"]).columns.tolist()
time_cols = df.select_dtypes(include=["datetime64"]).columns.tolist()
# 人工区分文本/普通类别:字符串平均长度区分
text_cols = []
pure_cat_cols = []
for c in cat_cols:
avg_len = df[c].astype(str).str.len().mean()
if avg_len > 15: # 长文本阈值可自定义
text_cols.append(c)
else:
pure_cat_cols.append(c)
print("数值特征:", num_cols)
print("纯类别特征:", pure_cat_cols)
print("文本特征:", text_cols)
print("时间特征:", time_cols)
六、EDA 输出产出物
一份 EDA 分析报告,包含:
- 数据集基础信息;
- 缺失值统计与处理建议;
- 各特征分布、异常值清单;
- 特征相关性、与目标变量关联度;
- 完整预处理、清洗、特征工程行动方案。

浙公网安备 33010602011771号