3、可视化分析:用Matplotlib/Seaborn绘制时间序列图、ACF、PACF
做时间序列分析,我个人的习惯是——先别急着建模,先画图。
你想想看,数据长什么样你都不知道,直接上模型那不是盲人摸象吗?可视化就是我们的眼睛。它能帮你快速判断数据有没有趋势、有没有季节性、是不是平稳。这些信息,光靠看数字表格是看不出来的。
这一节,我们就来聊聊怎么用Python把时间序列图、自相关图(ACF)和偏自相关图(PACF)画出来。我会结合我踩过的坑,给你一些实用建议。
3.1 准备工作:导入库与数据
先准备好工具。Matplotlib和Seaborn是主力,Pandas用来处理数据。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# 设置中文字体,防止乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成示例数据(模拟一个带趋势和季节性的时间序列)
np.random.seed(42)
dates = pd.date_range(start='2020-01-01', periods=200, freq='D')
trend = np.linspace(10, 20, 200)
seasonal = 5 * np.sin(2 * np.pi * np.arange(200) / 30)
noise = np.random.normal(0, 1, 200)
data = trend + seasonal + noise
df = pd.DataFrame({'date': dates, 'value': data})
df.set_index('date', inplace=True)
嗯,这里要注意:plt.rcParams 那两行一定要加。我之前在项目里没配中文字体,画出来的图全是方框,排查了半天才发现是字体问题。说白了,就是Matplotlib默认不支持中文,你得手动告诉它用哪个字体。
3.2 时间序列图:一眼看穿数据全貌
时间序列图就是把数据按时间顺序连成一条线。它能告诉你最直观的信息:数据是上升还是下降?有没有周期性波动?有没有明显的异常点?
plt.figure(figsize=(12, 5))
plt.plot(df.index, df['value'], color='#2E86AB', linewidth=1.5)
plt.title('时间序列图 - 原始数据', fontsize=14)
plt.xlabel('日期')
plt.ylabel('数值')
plt.grid(True, alpha=0.3)
plt.show()
画出来之后,你会看到一条整体向上、但带有波浪起伏的曲线。向上的部分就是趋势,波浪就是季节性。我在做电商销量预测时,就靠这张图一眼看出“双十一”前后的销量暴增——那叫一个明显。
plt.plot(..., marker='.', markersize=2),或者直接对数据做降采样,比如取每小时的平均值。
3.3 自相关图(ACF):找“自己跟自己的关系”
自相关,说白了就是当前时刻的值跟过去某个时刻的值有多像。比如今天的温度跟昨天的温度肯定有关系,但跟100天前的温度可能就没那么强了。
ACF图就是把这些相关系数画出来,横轴是滞后阶数(lag),纵轴是相关系数。
plt.figure(figsize=(12, 5))
plot_acf(df['value'], lags=40, alpha=0.05)
plt.title('自相关图 (ACF)', fontsize=14)
plt.xlabel('滞后阶数')
plt.ylabel('自相关系数')
plt.show()
你会看到:滞后1阶的相关系数很高(接近1),然后逐渐衰减。如果衰减很慢,说明数据有很强的趋势性,大概率是不平稳的。
3.4 偏自相关图(PACF):剔除中间变量的干扰
ACF有个问题:它会把间接相关也算进去。比如第1天影响第2天,第2天影响第3天,那第1天和第3天之间也有相关性,但这是间接的。
PACF就是剔除中间变量的干扰,只看“直接”的关系。比如第1天对第3天的直接影响有多大。
plt.figure(figsize=(12, 5))
plot_pacf(df['value'], lags=40, alpha=0.05, method='ywm')
plt.title('偏自相关图 (PACF)', fontsize=14)
plt.xlabel('滞后阶数')
plt.ylabel('偏自相关系数')
plt.show()
PACF图通常会在滞后1阶或2阶之后突然截断(掉到置信区间内)。这个特性特别有用——它直接告诉你AR模型应该用几阶。
- ACF拖尾(缓慢衰减)+ PACF截断(突然掉到区间内)→ 适合AR模型
- ACF截断 + PACF拖尾 → 适合MA模型
- 两者都拖尾 → 可能需要ARMA或差分
3.5 三图合一:对比着看更清楚
我习惯把时间序列图、ACF、PACF放在同一个画布里,这样能快速对照分析。
fig, axes = plt.subplots(3, 1, figsize=(12, 10))
# 时间序列图
axes[0].plot(df.index, df['value'], color='#2E86AB')
axes[0].set_title('时间序列图')
axes[0].set_ylabel('数值')
axes[0].grid(True, alpha=0.3)
# ACF
plot_acf(df['value'], lags=40, ax=axes[1])
axes[1].set_title('自相关图 (ACF)')
axes[1].set_xlabel('滞后阶数')
# PACF
plot_pacf(df['value'], lags=40, ax=axes[2], method='ywm')
axes[2].set_title('偏自相关图 (PACF)')
axes[2].set_xlabel('滞后阶数')
plt.tight_layout()
plt.show()
三张图放在一起,你就能看到:时间序列图显示有上升趋势和周期性波动;ACF显示自相关衰减很慢(趋势导致);PACF在滞后1阶和2阶显著,之后截断。这说明数据需要先做差分去除趋势,然后可以考虑AR(2)模型。
3.6 用Seaborn美化一下
Matplotlib是基础,但Seaborn能让图更好看。我个人比较喜欢Seaborn的默认配色和网格风格。
sns.set_style('whitegrid')
sns.set_palette('husl')
plt.figure(figsize=(12, 5))
sns.lineplot(data=df, x=df.index, y='value')
plt.title('时间序列图 - Seaborn风格', fontsize=14)
plt.xlabel('日期')
plt.ylabel('数值')
plt.show()
Seaborn的lineplot会自动处理置信区间(如果你有多条线的话),但单条线时它跟Matplotlib差不多。主要区别在于默认样式更现代一些。
sns.lineplot去画相关系数,结果发现跟plot_acf的结果对不上。后来才明白——plot_acf内部用的是statsmodels的计算逻辑,跟手动算相关系数有细微差别。所以画ACF和PACF,老老实实用plot_acf和plot_pacf,别自己造轮子。
3.7 本章知识体系
下面这张图帮你理清可视化分析的逻辑脉络:
说白了,这三张图就是时间序列分析的“三件套”。时间序列图看全局,ACF看整体相关性,PACF看直接关系。结合起来,你就能对数据有个八九不离十的判断。
我在实际项目中,经常是先画这三张图,然后心里就有数了——该不该差分、用AR还是MA、大概几阶。省下的时间,够你喝两杯咖啡的。