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 的直方图可能右偏——大部分时间浓度低,偶尔爆表。温度呢?可能是双峰分布,说明有「白天热、晚上冷」的规律。

看直方图时问自己三个问题

  1. 数据是单峰还是多峰?多峰可能意味着数据来自不同群体。
  2. 有没有明显的离群点?比如 PM2.5 在 150 附近有个小尾巴。
  3. 分布对称吗?不对称的话,后面建模可能需要做变换。

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 核心流程 描述性统计 df.describe() 相关性矩阵 df.corr() + 热力图 初步可视化 直方图 + 箱线图 每个步骤关注什么? 描述性统计 • 均值 vs 中位数 → 判断偏态 • 标准差 → 判断波动性 • min/max → 发现异常值 相关性矩阵 • 高相关特征 → 可能存在冗余 • 负相关特征 → 此消彼长 • 注意:相关 ≠ 因果 初步可视化 • 直方图 → 分布形态 • 箱线图 → 异常值检测 • 两者结合 → 全面了解

嗯,到这里,EDA 的三个核心步骤就讲完了。你可能会问:「这些图我画出来之后呢?」别急,下一章我们会讲如何用这些发现去做数据清洗和特征工程。但今天,先把 EDA 这一步练扎实了。

一句话总结:描述性统计让你知道数据「长什么样」,相关性矩阵告诉你特征「怎么抱团」,直方图和箱线图则帮你「看见」分布和异常。这三板斧抡好了,后面的分析就顺了。


公众号:蓝海资料掘金营,微信deep3321