3. 探索性数据分析(EDA)与可视化:用Pandas、Matplotlib、Seaborn摸清数据的脾气

说实话,很多初学者拿到数据就急着建模。我当年也犯过这个错——直接丢进回归模型,结果R²负得离谱。后来才明白,EDA不是走过场,是给数据做体检。你想想看,连数据长什么样都不知道,怎么指望模型能预测准?

这一节,我们就用Pandas做数据概览,用Matplotlib和Seaborn画趋势图、热力图,再聊聊数据分布特征。嗯,都是实战里每天要用的东西。

3.1 数据概览:Pandas三板斧

拿到数据后,我习惯先跑三个函数:head()info()describe()。别小看这三步,能帮你快速发现80%的问题。

import pandas as pd
import numpy as np

# 加载环境监测数据
df = pd.read_csv('air_quality.csv')

# 第一板斧:看前几行
print(df.head())

# 第二板斧:看数据类型和缺失值
print(df.info())

# 第三板斧:看统计摘要
print(df.describe())
我的习惯: 每次加载数据后,先看 info() 里的非空计数。如果某列缺失超过30%,我会考虑是否要删除或插补。曾经有一次,PM2.5数据缺失了40%,我直接用均值填充,结果模型偏差很大——后来改用时间序列插值才解决问题。

举个例子,假设数据长这样:

日期 温度(°C) 湿度(%) PM2.5(μg/m³) 风速(m/s)
2024-01-01 12.5 65.0 85.3 3.2
2024-01-02 14.1 58.0 72.1 4.5
2024-01-03 10.8 72.0 NaN 2.8

看到第三行PM2.5是NaN了吗?这就是info()能帮你快速定位的问题。

3.2 趋势图:时间序列的“心电图”

环境参数随时间变化,趋势图是最直观的观察方式。我个人喜欢用Matplotlib画折线图,配合Seaborn让图更漂亮。

import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 绘制PM2.5随时间变化趋势
plt.figure(figsize=(12, 5))
plt.plot(df['日期'], df['PM2.5'], color='#2E86AB', linewidth=1.5, marker='o', markersize=3)
plt.title('PM2.5浓度日变化趋势', fontsize=14)
plt.xlabel('日期')
plt.ylabel('PM2.5 (μg/m³)')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
关键观察点:
  • 是否有明显的周期性?比如早晚高峰PM2.5升高
  • 是否有异常突增或突降?可能是传感器故障或特殊事件
  • 整体趋势是上升还是下降?这关系到模型是否需要考虑时间漂移

我在项目中遇到过这样的情况:某工厂的废气排放数据,趋势图显示每周一数值特别高。后来一查,原来是周一设备检修后重新启动,排放不稳定。这个发现直接帮我们优化了预测模型——加入了“星期几”这个特征。

3.3 相关性热力图:谁和谁“关系好”?

回归模型最怕特征之间高度相关(多重共线性)。热力图能一眼看出哪些变量“抱团”。

# 计算相关系数矩阵
corr_matrix = df[['温度', '湿度', 'PM2.5', '风速', '气压']].corr()

# 绘制热力图
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f', 
            linewidths=0.5, square=True, cbar_kws={'shrink': 0.8})
plt.title('环境参数相关性热力图', fontsize=14)
plt.tight_layout()
plt.show()

热力图里,颜色越深表示相关性越强。红色是正相关,蓝色是负相关。举个例子:

温度 湿度 PM2.5 风速
温度 1.00 -0.45 0.12 -0.08
湿度 -0.45 1.00 0.68 -0.30
PM2.5 0.12 0.68 1.00 -0.55
风速 -0.08 -0.30 -0.55 1.00
避坑指南: 我曾经在做一个空气质量预测项目时,发现温度和湿度相关系数高达-0.45,但PM2.5和湿度相关系数0.68。当时没在意,直接丢进线性回归,结果模型系数符号都反了。后来用VIF(方差膨胀因子)一测,湿度这个特征的VIF超过10——明显多重共线性。解决办法:要么删除其中一个,要么用PCA降维。

3.4 数据分布特征:直方图与箱线图

数据分布决定了你该用什么模型。正态分布?偏态分布?有没有异常值?这些都得看。

# 绘制直方图 + 核密度估计
plt.figure(figsize=(10, 4))

plt.subplot(1, 2, 1)
sns.histplot(df['PM2.5'], bins=30, kde=True, color='#2E86AB')
plt.title('PM2.5分布直方图')

plt.subplot(1, 2, 2)
sns.boxplot(y=df['PM2.5'], color='#A23B72')
plt.title('PM2.5箱线图')

plt.tight_layout()
plt.show()

直方图能告诉你数据集中在哪个区间。比如PM2.5大多在50-100之间,但偶尔有超过200的——这些就是潜在异常值。

箱线图更直接:箱子中间的线是中位数,箱子范围是四分位距。超出“触须”的点就是异常值。我一般会这样处理:

  • 轻度异常(超出1.5倍IQR):保留,但做对数变换
  • 重度异常(超出3倍IQR):检查是否传感器故障,是则删除
  • 业务异常:比如PM2.5超过500,可能是沙尘暴事件,单独标记
一个小技巧: 如果数据严重右偏(比如污染物浓度),试试对数变换。我做过对比,对数变换后模型的R²从0.65提升到了0.81。说白了,就是让数据更“听话”。

3.5 知识体系:EDA的核心逻辑

下面这张图是我自己总结的EDA流程,每次做项目都照着走一遍:

EDA核心逻辑框架 ① 数据加载与概览 ② 缺失值与异常值检测 ③ 数据分布特征分析 ④ 趋势图与相关性分析 ⑤ 特征工程与建模准备 每个步骤的关键输出 • 数据维度、类型、缺失率 • 异常值位置与数量 • 偏度、峰度、正态性检验 • 时间趋势、周期性 • 相关系数矩阵 • 多重共线性诊断 • 特征选择建议 • 是否需要数据变换 • 是否需要降维 ⚠ 常见坑: 跳过EDA直接建模 忽略时间序列的平稳性

这个流程我用了好几年,每次做环境预测项目都按这个顺序来。说白了,EDA就是帮你在建模前把坑都踩一遍——总比模型跑出来才发现问题要好。

3.6 实战小贴士:EDA的“潜规则”

最后分享几个我踩过的坑:

  • 别只看相关系数:相关系数为0不代表没关系,可能是非线性关系。画个散点图矩阵看看。
  • 时间序列要检查平稳性:如果数据有趋势或季节性,直接用回归模型会出问题。我一般先用ADF检验。
  • 异常值不一定是错误:比如PM2.5突然飙升到500,可能是附近发生了火灾。这种异常值反而是重要信号,不能简单删除。
  • 可视化要“多角度”:同一个数据,折线图、直方图、箱线图看到的信息不一样。我习惯每个变量至少画两种图。

一句话总结: EDA做得好,建模事半功倍;EDA做得糙,模型跑得再快也是白搭。

专注资料整理