3. 探索性数据分析(EDA):描述性统计、相关性矩阵、初步可视化
好,咱们进入第三章。说实话,EDA 这一步,很多人觉得「不就是画几张图嘛」。但我在项目里吃过亏——数据没摸清楚就急着建模,结果模型跑出来一塌糊涂,回头一看,原来是数据分布本身就有问题。
所以,我个人的习惯是:先花 70% 的时间做 EDA,再用 30% 的时间建模。你想想看,数据长什么样你都不知道,模型再花哨也是白搭。
3.1 描述性统计:先给数据「拍个X光」
拿到数据第一件事,我会先跑个 df.describe()。这就像给数据拍了个 X 光片,能快速看到每个特征的均值、标准差、最小值、最大值、四分位数。
import pandas as pd
import numpy as np
# 假设 df 是你的环境数据集
print(df.describe())
输出大概长这样:
| 指标 | 温度 | 湿度 | PM2.5 | CO2 |
|---|---|---|---|---|
| count | 1000 | 1000 | 1000 | 1000 |
| mean | 22.5 | 65.3 | 35.2 | 412.0 |
| std | 3.2 | 12.1 | 18.7 | 85.6 |
| min | 15.0 | 30.0 | 5.0 | 350.0 |
| 25% | 20.0 | 55.0 | 20.0 | 380.0 |
| 50% | 22.0 | 66.0 | 30.0 | 400.0 |
| 75% | 25.0 | 75.0 | 45.0 | 430.0 |
| max | 35.0 | 95.0 | 150.0 | 800.0 |
重点看什么?
- 均值 vs 中位数:如果两者差距大,说明数据有偏态。比如 PM2.5 均值 35.2,中位数 30.0,说明有高值在拉高均值。
- 标准差:太大说明数据波动剧烈,太小说明变化平缓。
- min 和 max:一眼看出有没有异常值。比如温度 max 35°C,在室内环境里算正常吗?
我的小技巧:我习惯把 df.describe() 的结果转置一下看,尤其是特征多的时候。转置后每个特征一行,对比起来更直观。
3.2 相关性矩阵:找「抱团」的特征
描述性统计看的是单个特征,那特征之间的关系怎么看?相关性矩阵就是干这个的。
说白了,就是算两两特征之间的相关系数。我常用皮尔逊相关系数,取值范围 [-1, 1]。接近 1 是正相关,接近 -1 是负相关,接近 0 就是不相关。
# 计算相关性矩阵
corr_matrix = df.corr()
print(corr_matrix)
输出示例:
| 温度 | 湿度 | PM2.5 | CO2 | |
|---|---|---|---|---|
| 温度 | 1.00 | -0.45 | 0.12 | 0.08 |
| 湿度 | -0.45 | 1.00 | 0.35 | 0.22 |
| PM2.5 | 0.12 | 0.35 | 1.00 | 0.78 |
| CO2 | 0.08 | 0.22 | 0.78 | 1.00 |
我曾经踩过的坑:有一次我看到 PM2.5 和 CO2 相关系数 0.78,心想「这俩肯定有关系」。后来发现是因为它们都受同一个因素影响——通风系统开关。所以记住:相关性 ≠ 因果关系。别看到高相关就急着下结论。
我个人习惯把相关性矩阵用热力图可视化,这样一眼就能看出哪些特征「抱团」:
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f')
plt.title('特征相关性热力图')
plt.show()
3.3 初步可视化:直方图与箱线图
数字是冷冰冰的,图才是热乎乎的。我每次做 EDA,必画两种图:直方图和箱线图。
3.3.1 直方图:看分布形态
直方图能告诉你数据是正态分布、偏态分布,还是双峰分布。举个例子:
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.hist(df['PM2.5'], bins=30, color='skyblue', edgecolor='black')
plt.title('PM2.5 分布直方图')
plt.xlabel('PM2.5 浓度')
plt.ylabel('频数')
plt.subplot(1, 2, 2)
plt.hist(df['温度'], bins=30, color='salmon', edgecolor='black')
plt.title('温度分布直方图')
plt.xlabel('温度 (°C)')
plt.ylabel('频数')
plt.tight_layout()
plt.show()
你看,PM2.5 的直方图可能右偏——大部分时间浓度低,偶尔爆表。温度呢?可能是双峰分布,说明有「白天热、晚上冷」的规律。
看直方图时问自己三个问题:
- 数据是单峰还是多峰?多峰可能意味着数据来自不同群体。
- 有没有明显的离群点?比如 PM2.5 在 150 附近有个小尾巴。
- 分布对称吗?不对称的话,后面建模可能需要做变换。
3.3.2 箱线图:抓异常值的神器
箱线图我特别喜欢,因为它把五数概括(最小值、Q1、中位数、Q3、最大值)和异常值一起展示出来。
plt.figure(figsize=(8, 5))
sns.boxplot(data=df[['温度', '湿度', 'PM2.5', 'CO2']])
plt.title('环境数据箱线图')
plt.ylabel('数值')
plt.show()
箱线图里,那些「小圆点」就是异常值。我记得有一次做空气质量分析,箱线图显示某个监测站的 PM2.5 异常值特别多。后来一查,原来是那个站旁边在施工。你看,一张图就发现问题了。
怎么看箱线图?
- 箱子中间的线是中位数
- 箱子的上下边是 Q1 和 Q3
- 箱子外的「须」延伸到 1.5 倍 IQR 范围
- 须之外的点就是异常值
3.4 本章知识体系
下面这张图,是我自己总结的 EDA 核心流程。你照着这个顺序走,基本不会漏掉关键信息:
嗯,到这里,EDA 的三个核心步骤就讲完了。你可能会问:「这些图我画出来之后呢?」别急,下一章我们会讲如何用这些发现去做数据清洗和特征工程。但今天,先把 EDA 这一步练扎实了。
一句话总结:描述性统计让你知道数据「长什么样」,相关性矩阵告诉你特征「怎么抱团」,直方图和箱线图则帮你「看见」分布和异常。这三板斧抡好了,后面的分析就顺了。
公众号:蓝海资料掘金营,微信deep3321