拿到一份数据集后,第一件事往往不是急着训练模型,而是先弄清楚数据到底长什么样。探索性数据分析(Exploratory Data Analysis,简称EDA)就是用来回答这些问题的:数据有多少行多少列,哪些字段存在缺失,数值型特征的分布是否偏斜,类别型特征有多少种取值,变量之间是否存在明显的相关关系。这一阶段的工作质量,直接决定了后续特征工程和建模的成效。Python生态中,pandas、matplotlib、seaborn等库为EDA提供了非常完备的工具链。

本文以一份模拟的电商订单数据集为例,演示从数据加载、结构检查、缺失值处理到分布与相关性分析的完整流程。整个分析过程使用常见的Jupyter Notebook环境,代码结构清晰,可以直接复制到自己的项目中反复使用。
一、数据加载与初步检查
任何EDA的第一步都是把数据读进内存。pandas库提供了读取CSV、Excel、JSON等格式数据的方法,其中read_csv是出场率最高的一个。读取时可以提前指定日期字段的解析方式,也可以先不指定,等观察完数据形态再做调整。数据加载完成后,不要急着一股脑查看全部数据,而是先用head、info、describe这三个方法快速建立对数据集的整体印象。
import pandas as pd
df = pd.read_csv('order_data.csv', parse_dates=['order_date'])
print(df.shape) # 查看行数和列数
df.head() # 查看前5行数据
df.info() # 查看列名、非空数量与数据类型
df.describe() # 查看数值列的统计描述加载完成后,distinct.info方法会输出一张表格,包含每列的名称、非空计数和数据类型。通过这张表,能立刻判断出哪些列存在缺失值,哪些列的类型设置可能不合理。比如订单编号id列被读成了int64,但实际上它只是一个字符串形式的业务编号,并不参与数值运算,这时就应该把它转成object类型。再看describe的输出,默认只对数值列统计,包括均值、标准差、最小值、四分位数和最大值。这些统计量能帮你快速判断数据是否落入合理范围,例如订单金额如果出现了负值,或者用户年龄列出现了200,那显然数据存在异常。
对于分类特征,除了info方法给出的非空计数,还可以用value_counts来统计每个类别的出现次数。把类别分布打印出来,能发现某些类别的样本量极不均衡。这种不均衡在后续建模时可能会引发偏差,需要在EDA阶段记录下异常情况,在特征工程时做针对性处理。
二、缺失值与重复值处理
缺失值是数据质量分析中最常见的问题。pandas里用isnull配合sum可以逐列统计缺失数量,但更直观的做法是借助seaborn的heatmap画出缺失值热力图,或者用missingno库来看缺失分布。不同列的缺失模式往往能透露很多信息,例如某个字段的缺失值可能集中在特定时间段,这通常意味着数据采集流程存在某种系统性偏差。
import seaborn as sns
import matplotlib.pyplot as plt
# 统计每列缺失数量
missing_count = df.isnull().sum()
missing_count = missing_count[missing_count > 0].sort_values(ascending=False)
print(missing_count)
# 缺失值热力图
plt.figure(figsize=(10, 6))
sns.heatmap(df.isnull(), cbar=False, yticklabels=False, cmap='viridis')
plt.title('缺失值分布热力图')
plt.show()
# 移除完全重复的行
duplicate_rows = df.duplicated().sum()
print(f'重复行数量: {duplicate_rows}')
df_clean = df.drop_duplicates().reset_index(drop=True)处理缺失值时有多种策略。如果某一列的缺失比例超过50%,通常可以直接考虑删除整个列,因为缺失信息过多时,填充带来的偏差往往比删除更大。如果缺失比例较低,数值型字段可用中位数或均值填充,类别型字段可用众数填充,也可以把缺失值本身当作一个新类别。值得强调的是,XGBoost、LightGBM这类梯度提升树模型原生支持缺失值处理,因此使用这些算法时,在EDA阶段只需记录缺失情况,不必急着填充。
重复值同样不能掉以轻心。df.duplicated方法会标记重复的行,keep参数可以控制保留哪一条。在真实业务数据中,由于上游系统重复推送或者程序重试机制的问题,同一笔订单可能被记录多次。如果不加处理,这些重复记录会虚增各类统计指标,直接影响模型训练的效果。清理重复数据时,还应先确认重复行的所有字段是否完全一致,如果部分字段不一致,需要结合创建时间、更新状态等信息判断保留哪一条记录更可靠。
三、数值特征分布与离群值检测
了解数值特征的分布形态是EDA的核心任务。很多机器学习模型对输入特征的分布有假设要求,比如线性回归假设误差服从正态分布。对于数值型特征,可以用直方图加核密度曲线叠加的方式来观察数据是否符合近似正态分布。如果出现明显的长尾分布,比如用户消费金额集中在低区间,而少数大额订单把均值拉得很高,后续可以考虑使用对数变换来缓解偏态问题。
import numpy as np
# 创建2行3列的子图
fig, axes = plt.subplots(2, 3, figsize=(15, 8))
numeric_cols = ['order_amount', 'item_count', 'discount_rate',
'user_age', 'total_cost', 'profit']
for ax, col in zip(axes.flatten(), numeric_cols):
# 直方图与核密度估计
sns.histplot(df_clean[col], kde=True, ax=ax, color='steelblue')
ax.set_title(f'{col} 的分布')
plt.tight_layout()
plt.show()
# 箱线图检测离群值
plt.figure(figsize=(12, 6))
sns.boxplot(data=df_clean[['order_amount', 'item_count', 'discount_rate']])
plt.xticks(rotation=45)
plt.title('数值特征的箱线图')
plt.show()箱线图是检测离群值最常用的可视化工具。它基于四分位数和IQR(四分位距)来定义离群点,通常把低于Q1-1.5*IQR或高于Q3+1.5*IQR的点视为离群值。需要注意,离群值并不等于错误值,它背后可能隐藏着重要的业务含义,比如大客户的高额订单,也可能是用户误操作产生的异常数据。正确的做法是先把离群值单独提取出来,结合业务场景逐一确认,再决定是删除、截尾处理还是保留。
如果数据集中存在经纬度、时间戳这类特殊字段,还可以计算一些衍生统计量,比如两个时间点之间的间隔天数。这些衍生指标本身也值得画分布图观察。只要时间允许,对每一条数值特征都做一次分布检查,并给每个特征写下一两行注释,整个数据分析流程的后面阶段会顺畅很多。
四、类别特征分析与多变量相关性
类别特征的EDA手段主要是频数统计和柱状图。对于取值过多的类别特征,可以先按频数排序,取前N个高频类别,把其余低频类别统一归为其他类,这样可视化时不会被大量低频类别挤占空间。类别特征之间还可以使用交叉表和卡方检验来观察关联性,比如用户所在城市和支付方式之间是否存在显著关系。
import pandas as pd
# 频数统计并可视化
top_categories = df_clean['category'].value_counts().head(10)
print(top_categories)
# 交叉表观察类别间关系
crosstab = pd.crosstab(df_clean['category'], df_clean['payment_method'])
print(crosstab.head())
# 数值特征的相关性矩阵
corr_matrix = df_clean[numeric_cols].corr(method='pearson')
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm',
linewidths=0.5, linecolor='white')
plt.title('数值特征相关性热力图')
plt.show()相关性分析主要用来衡量数值型变量之间的线性相关程度。pandas的corr方法默认计算皮尔逊相关系数,返回值是一个对称矩阵。数据量较小时可以直接查看数值矩阵,数据量较大时用seaborn的热力图更直观。如果发现两个特征之间的相关系数超过0.9,意味着存在多重共线性风险,在线性回归和逻辑回归这类模型中对系数估计影响明显,通常的解决办法是删除其中一个特征,或者利用主成分分析把相关特征合并后再建模。
要注意的是,皮尔逊相关系数只描述线性关系,两个变量之间的关系如果呈现明显的U型或者指数型,线性相关可能接近0,但这不代表它们之间没有关联。这种情况可以借助分组统计来进一步探索。例如先把特征A按数值区间分成多段,再计算每个区间内特征B的均值,通过均值的变化趋势来判断是否存在非线性的规律。
五、高效自动化的EDA报告工具
如果数据集包含几十甚至上百个字段,手动逐个画图会非常耗时。ydata-profiling库可以在几秒钟内自动生成一份交互式的完整报告,其中包含数据概览、字段统计、缺失值矩阵、相关性热力图以及变量间的交互分析。早期版本的库名为pandas-profiling,现在官方推荐使用ydata-profiling,API基本保持一致。
from ydata_profiling import ProfileReport
report = ProfileReport(df_clean, title='电商订单数据EDA报告', minimal=False)
report.to_file('eda_report.html')
# 如果只想要快速概览,可以启用minimal模式
quick_report = ProfileReport(df_clean, minimal=True)
quick_report.to_file('eda_quick_report.html')这份自动生成的报告覆盖了手工EDA的绝大部分内容,尤其适合在项目初期快速摸清数据全貌。不过它也存在局限性,比如自动报告不会考虑业务背景,不会告诉你某个离群值可能是营销活动导致的,也不会提醒你哪个字段在业务KPI分析中更重要。因此,建议把自动报告当作一个起点,而不是终点。
更合理的做法是,先用ydata-profiling快速生成报告,再从报告的图表中发现值得深挖的方向,比如某个特征分布异常,或者两个变量间的相关性出乎意料,接下来再回到代码环境中针对性地做细粒度分析。这种自动筛查加人工深挖的配合模式,在大型数据集上能节省大量时间。
总结:让EDA成为一种分析习惯
EDA不是一次性的交付物,它贯穿数据分析和机器学习的整个生命周期。拿到数据后先做整体结构检查,然后逐步处理缺失、重复、离群问题,再进行分布观察和相关性分析,每一步都会加深对数据的理解。通过结构化的流程,可以把原始数据变成有价值的信息资产,为后续的特征工程和模型调优打下扎实基础。
上面介绍的方法和代码覆盖了最常见的数据探索场景。实际项目中,你可能会遇到时序数据、文本数据、图像特征等更复杂的类型,届时还需要引入word frequency、MFCC特征、embedding降维等更多EDA手段。但无论数据类型怎么变化,核心思想始终不变——带着明确的问题去观察数据,用批判的眼光去验证每一个假设,最终让数据自己揭示出隐藏在其中的规律。
Python数据探索探索性数据分析EDA修改时间:2026-08-27 08:54:26