3. 时间序列分解:趋势、季节性与残差
时间序列分解,说白了就是把一串乱糟糟的数据拆成几块有规律的东西。我刚开始做量化的时候,面对一堆价格数据,第一反应就是直接建模。结果呢?模型跑出来一塌糊涂。后来才明白,不先把数据拆开看看,就像医生不拍片子直接开药,太莽撞了。
今天咱们就聊聊怎么拆。核心就三个成分:趋势、季节性、残差。再加上两种拆法:加法模型和乘法模型。
3.1 三个成分,各是什么?
先给个直观理解:
- 趋势(Trend):长期来看,数据是往上走还是往下走。比如A股过去十年,整体是震荡向上的。注意,是“长期”,不是短期波动。
- 季节性(Seasonality):固定周期内的重复模式。比如电商销售额,每年双十一前后都会冲一波。周期可以是年、季度、月,甚至一周。
- 残差(Residual):去掉趋势和季节性之后,剩下的随机波动。说白了就是“噪音”。如果残差里还有规律,说明你分解得不够干净。
我个人的习惯是,拿到数据先画个图。看一眼趋势,再找找有没有周期性波动。如果连图都不看就上模型,那跟闭着眼开车差不多。
3.2 加法模型 vs 乘法模型
这两种模型,区别在于成分之间怎么组合。
| 模型 | 公式 | 适用场景 |
|---|---|---|
| 加法模型 | Y = T + S + R | 季节性波动幅度不随趋势变化 |
| 乘法模型 | Y = T × S × R | 季节性波动幅度随趋势放大或缩小 |
举个例子。你想想看,一家小公司的月销售额,季节性波动可能是±10万。如果公司做大了,销售额翻倍,季节性波动可能变成±20万。这时候用乘法模型更合适。如果波动幅度一直不变,那就用加法模型。
核心判断标准:看季节性波动的幅度是否与趋势水平成正比。
我在项目中遇到过一件事。有一次分析某商品的日销量数据,趋势是缓慢上升的,但季节性波动看起来越来越大。我一开始用了加法模型,结果残差里还残留着明显的季节性模式。后来换成乘法模型,残差才变得干净。嗯,这里要注意:选错模型,残差会“说谎”。
3.3 怎么分解?经典方法
最常用的方法是移动平均分解。步骤很简单:
- 用移动平均估计趋势 T。
- 从原序列中减去趋势,得到“去趋势序列”。
- 对去趋势序列按周期平均,得到季节性成分 S。
- 从原序列中减去 T 和 S,得到残差 R。
如果是乘法模型,步骤类似,只是把减法换成除法。
下面给一段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('2020-01-01', periods=365, freq='D')
trend = np.linspace(100, 200, 365)
seasonality = 10 * np.sin(2 * np.pi * np.arange(365) / 30)
noise = np.random.normal(0, 2, 365)
data = trend + seasonality + noise
# 分解
result = seasonal_decompose(data, model='additive', period=30)
# 画图
result.plot()
plt.show()
这段代码跑完之后,你会看到四张图:原始数据、趋势、季节性、残差。一眼就能看出分解得干不干净。
小技巧:如果数据是日频,周期参数 period 要设对。比如周周期设7,月周期设30。设错了,分解出来的季节性就是错的。我曾经因为把月周期设成365,结果季节性完全看不出规律,折腾了半天才发现是参数问题。
3.4 避坑指南:残差里还有规律怎么办?
分解完之后,一定要看一眼残差图。如果残差里还有明显的周期性或趋势,说明分解不彻底。常见原因有两个:
- 周期选错了:比如数据有双周期(周周期和月周期),你只分解了一个。
- 模型选错了:加法模型和乘法模型搞反了。
我曾经遇到一个案例,某金融时间序列的残差里总是有“尖峰”。后来发现,是因为数据里有一个异常值,把移动平均拉偏了。处理办法是:先做异常值检测,再分解。顺序很重要。
警告:不要盲目相信分解结果。尤其是金融数据,经常有结构性突变(比如政策变化、黑天鹅事件)。这些突变会被分解到残差里,但其实是“信号”而不是“噪音”。
3.5 知识体系总览
下面这张图,是我自己总结的时间序列分解核心逻辑。你看一眼,基本就能把今天的内容串起来。
这张图的核心就一句话:先判断波动幅度是否随趋势变化,再选模型,最后拆出三个成分。别搞反了顺序。
3.6 实战中的一点感悟
时间序列分解这件事,看起来简单,但做起来容易翻车。我个人的经验是:
- 先画图,再分解。图能告诉你很多信息,比如有没有缺失值、有没有异常点。
- 分解之后,一定要检查残差。残差如果还有规律,说明你漏掉了什么。
- 不要迷信自动分解。有些库的默认参数不一定适合你的数据。
说白了,分解不是目的,目的是理解数据背后的生成机制。你拆得越干净,后续建模就越有底气。
公众号:蓝海资料掘金营,微信deep3321