4、时序数据分析基础:时间序列分解(趋势、季节、残差)、自相关分析、平稳性检验

各位同学,咱们今天聊点实在的。做削峰填谷,说白了就是跟时间序列打交道。你连数据的基本规律都摸不透,怎么去削?怎么去填?

我个人习惯,拿到任何时序数据,第一件事不是建模,而是先做三件事:分解、看相关性、测平稳性。这三板斧下去,数据的大致脾气你就摸透了。

4.1 时间序列分解:把数据拆开看

时间序列分解,就是把一个复杂的时间序列,拆成几个简单的部分。我一般拆成三块:趋势、季节、残差

  • 趋势(Trend):长期来看,数据是往上走还是往下走?比如用电量,随着经济发展,整体趋势是上升的。
  • 季节(Seasonal):固定周期内的波动。比如一天24小时,用电高峰在白天;一年四季,夏天用电多。
  • 残差(Residual):去掉趋势和季节后剩下的随机波动。说白了,就是“运气成分”或者“异常事件”。

核心公式:

加法模型:Y(t) = Trend(t) + Seasonal(t) + Residual(t)

乘法模型:Y(t) = Trend(t) × Seasonal(t) × Residual(t)

我建议,如果季节波动幅度随趋势变化,用乘法模型;如果波动幅度稳定,用加法模型。

我在项目中遇到过,有个同学直接用加法模型去拟合用电量数据,结果残差越来越大。为什么?因为夏天用电量基数大,波动自然大,乘法模型才合适。

4.1.1 动手分解一下

Python里用 statsmodels 库,几行代码就搞定。我给你们写个例子:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose

# 生成模拟数据:趋势上升 + 季节波动 + 随机噪声
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=365, freq='D')
trend = np.linspace(100, 200, 365)  # 线性上升趋势
seasonal = 10 * np.sin(2 * np.pi * np.arange(365) / 7)  # 周周期
residual = np.random.normal(0, 2, 365)
data = trend + seasonal + residual

# 分解
result = seasonal_decompose(data, model='additive', period=7)

# 画图
fig, axes = plt.subplots(4, 1, figsize=(12, 8))
axes[0].plot(data, label='原始数据')
axes[0].legend()
axes[1].plot(result.trend, label='趋势', color='orange')
axes[1].legend()
axes[2].plot(result.seasonal, label='季节', color='green')
axes[2].legend()
axes[3].plot(result.resid, label='残差', color='red')
axes[3].legend()
plt.tight_layout()
plt.show()

小提示:分解时 period 参数很关键。如果是日数据,周周期设7;如果是小时数据,日周期设24。设错了,分解出来的季节成分就是错的。

4.2 自相关分析:数据跟自己“攀亲戚”

自相关,说白了就是看当前时刻的数据,跟过去某个时刻的数据有没有关系。比如今天下午3点的用电量,跟昨天下午3点的用电量,是不是很像?

我常用两个工具:ACF(自相关函数)PACF(偏自相关函数)

  • ACF:衡量当前值跟所有滞后值之间的相关性。比如今天跟昨天、前天、大前天的关系。
  • PACF:剔除中间变量后,当前值跟特定滞后值之间的“纯”相关性。比如今天跟大前天的关系,但要去掉昨天和前天的影响。

你想想看,如果ACF图衰减很慢,说明数据有很强的趋势性,大概率不平稳。如果ACF在某个滞后阶数后突然截尾,那可能就是季节周期的长度。

4.2.1 画个ACF图看看

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

# 画ACF和PACF
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(data, lags=30, ax=axes[0])
plot_pacf(data, lags=30, ax=axes[1])
plt.show()

避坑指南:我曾经在分析一个流量数据时,ACF图显示所有滞后阶数都显著,我以为周期很长。后来才发现,是因为数据有缺失值,插值后引入了虚假的自相关。所以,先处理缺失值,再做自相关分析

4.3 平稳性检验:数据“稳不稳”

平稳性,是时间序列建模的前提。什么叫平稳?简单说,就是数据的统计性质(均值、方差)不随时间变化。

为什么要检验平稳性?因为很多模型(比如ARIMA)要求数据平稳。不平稳的数据,模型会学出虚假的规律。

我常用的检验方法是ADF检验(Augmented Dickey-Fuller Test)

  • 原假设H0:序列存在单位根(不平稳)。
  • 备择假设H1:序列平稳。
  • 判断标准:p值 < 0.05,拒绝原假设,认为序列平稳。

4.3.1 代码实现

from statsmodels.tsa.stattools import adfuller

# ADF检验
result = adfuller(data)
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
print(f'临界值:')
for key, value in result[4].items():
    print(f'  {key}: {value:.4f}')

if result[1] < 0.05:
    print('结论:序列平稳')
else:
    print('结论:序列不平稳,需要差分')

输出示例:

指标
ADF统计量 -3.4567
p值 0.0098
1%临界值 -3.4325
5%临界值 -2.8624
10%临界值 -2.5672

p值0.0098 < 0.05,拒绝原假设,序列平稳。

嗯,这里要注意。如果数据不平稳,怎么办?差分。一阶差分不行就二阶差分。但别差太多,否则会丢失信息。我一般最多差到二阶。

4.4 知识体系总览

为了让你更直观地理解这三块内容的关系,我画了张图:

时序数据分析基础:核心知识体系 时序数据 时间序列分解 自相关分析 平稳性检验 趋势 季节 残差 ACF PACF ADF检验 差分 目的:理解数据规律,为削峰填谷建模做准备

这张图把今天讲的内容串起来了。你从时序数据出发,先做分解,再看自相关,最后测平稳性。每一步都有对应的工具和方法。

我的习惯:在实际项目中,我会先画一张这样的知识地图,然后对着地图一步步执行。这样不容易漏掉关键步骤。

好了,今天的内容就到这里。记住,时序数据分析不是一蹴而就的,多动手、多画图、多思考。你把这些基础打牢了,后面做削峰填谷模型,自然水到渠成。


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