3、数据探索性分析(EDA):描述性统计、数据分布可视化、相关性分析
数据拿到手,别急着建模。
这是我踩过无数次坑之后,最想对你说的一句话。你想想看,一堆数据扔过来,连它长什么样、有没有异常、变量之间什么关系都不清楚,直接上模型,结果多半是灾难。
EDA,说白了就是给数据做体检。我习惯把它分成三步走:先看描述性统计,再画分布图,最后做相关性分析。这三板斧抡下来,数据的基本盘就摸透了。
3.1 描述性统计:先摸清数据的底细
描述性统计是最基础的一步。它回答几个核心问题:数据集中趋势如何?离散程度多大?有没有缺失值?
我个人习惯用 pandas 的 describe() 方法,一行代码就能看到均值、标准差、四分位数等关键指标。
import pandas as pd
# 加载数据
df = pd.read_csv('sales_data.csv')
# 描述性统计
print(df.describe())
输出结果长这样:
| 指标 | 销售额 | 客户年龄 | 购买次数 |
|---|---|---|---|
| count | 1000 | 1000 | 1000 |
| mean | 256.3 | 34.5 | 12.1 |
| std | 89.2 | 12.3 | 8.7 |
| min | 0.0 | 18.0 | 1.0 |
| 25% | 180.0 | 25.0 | 5.0 |
| 50% | 250.0 | 32.0 | 10.0 |
| 75% | 320.0 | 42.0 | 18.0 |
| max | 9999.0 | 120.0 | 99.0 |
关键点:看到 max 值了吗?销售额最大是 9999,而 75% 分位数才 320。这明显是异常值。我在项目中遇到过类似情况,后来发现是某个促销活动期间的数据录入错误。
除了 describe(),我还会单独检查缺失值:
# 检查缺失值
print(df.isnull().sum())
小技巧:缺失值比例超过 30% 的列,我一般直接删除。低于 5% 的,用均值或中位数填充。中间那档,得看业务场景决定。
3.2 数据分布可视化:一图胜千言
描述性统计只能给你数字,但数字有时候会骗人。举个例子,两组数据的均值和标准差可能完全一样,但分布形态天差地别。这就是安斯库姆四重奏告诉我们的道理。
所以,一定要画图。
3.2.1 直方图与箱线图
直方图看分布形态,箱线图看异常值。这两个是黄金搭档。
import matplotlib.pyplot as plt
import seaborn as sns
# 直方图
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
sns.histplot(df['销售额'], bins=30, kde=True)
plt.title('销售额分布')
# 箱线图
plt.subplot(1, 2, 2)
sns.boxplot(y=df['销售额'])
plt.title('销售额箱线图')
plt.tight_layout()
plt.show()
直方图里如果出现长尾,说明数据右偏。箱线图里那些小圆点,就是异常值。嗯,这里要注意:异常值不一定是错误,可能是真实的极端情况。我曾经处理过一份金融数据,那些「异常值」其实是高净值客户的交易记录,删掉反而会丢失重要信息。
3.2.2 分类变量的分布
对于分类变量,用柱状图或者饼图。我更喜欢柱状图,因为饼图在类别多的时候根本看不清。
# 分类变量分布
sns.countplot(x='地区', data=df)
plt.title('各地区客户数量')
plt.show()
避坑指南:我曾经在分析用户画像时,发现某个地区的客户数量异常少。一开始以为是数据采集问题,后来才发现是那个地区的业务员根本没录入数据。所以,分布图不仅能看数据,还能反推数据质量。
3.3 相关性分析:变量之间的悄悄话
变量之间有没有关系?是正相关还是负相关?强度如何?这是相关性分析要回答的问题。
3.3.1 皮尔逊相关系数
最常用的是皮尔逊相关系数,取值范围 [-1, 1]。0.8 以上算强相关,0.3 以下算弱相关。
# 计算相关系数矩阵
corr_matrix = df.corr()
print(corr_matrix)
输出示例:
| 销售额 | 客户年龄 | 购买次数 | |
|---|---|---|---|
| 销售额 | 1.00 | 0.12 | 0.85 |
| 客户年龄 | 0.12 | 1.00 | 0.08 |
| 购买次数 | 0.85 | 0.08 | 1.00 |
看到没?销售额和购买次数的相关系数是 0.85,强相关。这符合直觉:买得越多,销售额越高。但客户年龄和销售额只有 0.12,基本没关系。
3.3.2 热力图可视化
数字矩阵看着累,热力图就直观多了。
# 热力图
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f')
plt.title('相关性热力图')
plt.show()
颜色越深,相关性越强。红色代表正相关,蓝色代表负相关。一眼就能看出哪些变量是「铁哥们」,哪些是「陌生人」。
重要提醒:相关性不等于因果性。我见过太多人看到两个变量相关,就以为一个导致另一个。比如冰淇淋销量和溺水人数正相关,但真正的原因是夏天到了。所以,相关性分析只是线索,不是结论。
3.3.3 散点图矩阵
当变量比较多的时候,散点图矩阵能一次性展示所有两两关系。
# 散点图矩阵
sns.pairplot(df[['销售额', '客户年龄', '购买次数', '客单价']])
plt.show()
对角线是分布图,非对角线是散点图。如果某个散点图呈现出明显的线性趋势,那这两个变量大概率有故事。
3.4 EDA 知识体系总览
下面这张图,是我自己总结的 EDA 核心流程。每次做数据分析前,我都会对照着走一遍。
这张图把 EDA 的三大块串起来了。从左到右,从上到下,每一步都有对应的工具和方法。你照着这个框架走,基本不会漏掉关键信息。
我的习惯:每次做完 EDA,我都会写一个简短的总结文档,记录发现了什么异常、哪些变量值得深挖、数据质量如何。这个文档后面建模的时候会反复用到,省得回头再查。
好了,EDA 的核心内容就这些。说白了,就是让你和数据建立「亲密关系」。你越了解它,它就越不会在建模的时候给你挖坑。