4. 时间序列分析入门:平稳性检验、自相关函数、偏自相关函数

做风电功率预测,说白了就是在跟时间打交道。你拿到的数据,是一串按时间顺序排列的功率值——今天、昨天、前天……这玩意儿就叫时间序列。

但问题来了:不是所有的时间序列都能直接拿来建模。我刚开始做风电项目时,拿到数据就往上套模型,结果预测结果一塌糊涂。后来才发现,我压根没搞清楚这组数据的“脾气”。

所以,在动手建模之前,咱们得先做三件事:平稳性检验自相关函数(ACF)偏自相关函数(PACF)。这三板斧,能帮你摸清数据的底细。

时间序列分析入门:核心三要素 时间序列预处理 平稳性检验 自相关函数 (ACF) 偏自相关函数 (PACF) ADF检验 / KPSS检验 识别MA阶数 识别AR阶数 三者结合 → 确定ARIMA模型参数 (p, d, q)

4.1 平稳性检验:数据到底稳不稳?

什么叫平稳?简单说,就是数据的统计性质不随时间变化。均值稳定、方差稳定、自相关结构也稳定。

你想想看,如果今天的功率均值是100MW,明天突然跳到500MW,后天又掉回80MW——这种数据你拿什么模型去预测?模型会疯掉的。

我个人习惯,拿到时间序列第一件事就是画图。用肉眼看,数据有没有明显的趋势或季节性波动。

import pandas as pd
import matplotlib.pyplot as plt

# 假设 df 是包含风电功率数据的 DataFrame,索引为时间
plt.figure(figsize=(12, 4))
plt.plot(df.index, df['power'], color='#2c5f8a')
plt.title('风电功率时间序列')
plt.xlabel('时间')
plt.ylabel('功率 (MW)')
plt.grid(True, alpha=0.3)
plt.show()

光看图还不够,得用统计检验说话。最常用的是ADF检验(Augmented Dickey-Fuller Test)。

核心思想:如果p值小于0.05,就拒绝“存在单位根”的原假设,说明序列是平稳的。

from statsmodels.tsa.stattools import adfuller

result = adfuller(df['power'].dropna())
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')

if result[1] < 0.05:
    print('✅ 序列平稳,可以继续建模')
else:
    print('❌ 序列不平稳,需要差分处理')

我在项目中遇到过这样的情况:ADF检验说序列平稳,但模型效果就是不好。后来发现,数据虽然均值稳定,但方差在波动——这叫“异方差性”。所以有时候还得配合KPSS检验一起看,两个检验互相验证。

我的小技巧:如果ADF检验不通过,先做一阶差分。差分后的数据90%以上都能变平稳。如果还不平稳,那就考虑二阶差分,但别超过二阶,否则会丢失太多信息。

4.2 自相关函数(ACF):数据跟过去的自己有多像?

自相关函数,说白了就是衡量当前时刻的功率值,跟过去某个时刻的功率值之间的相关性。

比如,今天的功率跟昨天的功率有关系吗?跟三天前的呢?ACF就是把这些相关性画成一张图。

from statsmodels.graphics.tsaplots import plot_acf
import matplotlib.pyplot as plt

plot_acf(df['power'].dropna(), lags=30, alpha=0.05)
plt.title('自相关函数 (ACF)')
plt.xlabel('滞后阶数')
plt.ylabel('自相关系数')
plt.grid(True, alpha=0.3)
plt.show()

ACF图怎么看?记住两点:

  • 蓝色区域:置信区间。柱子超出蓝线,说明该滞后阶数的相关性显著。
  • 衰减模式:如果ACF缓慢衰减(拖尾),说明序列有自回归特性;如果ACF在某个阶数后突然截断,说明有滑动平均特性。

嗯,这里要注意:ACF的“拖尾”和“截断”是判断ARIMA模型阶数的关键。我刚开始学的时候,总把这两个概念搞混。后来老师教了我一个口诀——“ACF拖尾定AR,ACF截断定MA”

避坑指南:我曾经在分析风电数据时,ACF图显示滞后1阶和滞后2阶都显著,但滞后3阶突然不显著了。我以为是截断,结果模型拟合效果很差。后来发现,那是因为数据量不够大,置信区间太宽导致的误判。所以,样本量至少要有50个以上,ACF图才可靠。

4.3 偏自相关函数(PACF):剔除干扰后的“纯净”相关性

ACF有个问题:它会把间接相关也算进去。比如,今天的功率跟三天前的功率相关,但可能只是因为今天跟昨天相关,昨天又跟前天相关,前天再跟三天前相关——这中间隔了好几层。

PACF就是干这个的:它剔除了中间所有滞后阶数的影响,只保留“纯净”的直接相关性。

from statsmodels.graphics.tsaplots import plot_pacf

plot_pacf(df['power'].dropna(), lags=30, alpha=0.05, method='ywm')
plt.title('偏自相关函数 (PACF)')
plt.xlabel('滞后阶数')
plt.ylabel('偏自相关系数')
plt.grid(True, alpha=0.3)
plt.show()

PACF的解读跟ACF正好相反:

  • PACF截断:说明数据适合用自回归模型(AR),截断的阶数就是AR的阶数p。
  • PACF拖尾:说明数据适合用滑动平均模型(MA)。

为什么会这样?你想想看,如果PACF在滞后2阶后突然掉到置信区间内,那就说明当前值只跟最近2个时刻的值有直接关系,更早的值都是间接影响。这不就是AR(2)模型嘛。

实战口诀:

  • ACF拖尾 + PACF截断 → AR模型(看PACF截断阶数定p)
  • ACF截断 + PACF拖尾 → MA模型(看ACF截断阶数定q)
  • ACF拖尾 + PACF拖尾 → ARMA模型(需要结合AIC/BIC定阶)

4.4 三者结合:给ARIMA模型定阶

平稳性检验、ACF、PACF,这三者不是孤立的。它们共同服务于一个目标:确定ARIMA模型的三个参数——p(自回归阶数)、d(差分阶数)、q(滑动平均阶数)

具体流程是这样的:

  1. 先做平稳性检验:如果不平稳,做差分,直到平稳。差分的次数就是d。
  2. 再看ACF和PACF:根据它们的拖尾/截断模式,初步确定p和q的范围。
  3. 最后用AIC/BIC定阶:在初步范围内遍历,选AIC或BIC最小的组合。
import itertools
from statsmodels.tsa.arima.model import ARIMA

# 假设已经差分到平稳,d=1
d = 1
p_range = range(0, 4)  # 尝试p=0,1,2,3
q_range = range(0, 4)  # 尝试q=0,1,2,3

best_aic = float('inf')
best_order = None

for p, q in itertools.product(p_range, q_range):
    try:
        model = ARIMA(df['power'], order=(p, d, q))
        result = model.fit()
        if result.aic < best_aic:
            best_aic = result.aic
            best_order = (p, d, q)
    except:
        continue

print(f'最优模型阶数: p={best_order[0]}, d={best_order[1]}, q={best_order[2]}')
print(f'AIC值: {best_aic:.2f}')

我的经验:别完全迷信AIC/BIC。有时候它们选出来的阶数虽然统计上最优,但实际预测效果不一定最好。我一般会选2-3个候选模型,都跑一遍,看看残差是不是白噪声,再决定用哪个。

好了,时间序列分析入门就聊到这儿。平稳性检验、ACF、PACF,这三板斧你掌握了,后面建模就顺了。记住,数据预处理花的时间,永远值得。


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