4.3 季节性调整:X-13ARIMA-SEATS


4.3 季节性调整:X-13ARIMA-SEATS

本节摘要:季节性调整是把季节性从数据中"剥掉",让调整后序列能反映真实的同比变化。X-13ARIMA-SEATS 是美国人口普查局 / 欧统局联合开发的事实标准,被各国统计局广泛使用。本节给出它的核心思想、Python 接口(statsmodels)以及一份对比"调整前/调整后"销量序列的完整案例。

本节学习地图

阅读完本节,你应当能够:

  1. 解释季节性调整的目的:让"今年的 8 月"和"去年的 8 月"可比。
  2. 区分 X-13ARIMA-SEATS 与简单移动平均法在季节性调整上的差异。
  3. 用 statsmodels 跑一次 X-13 调整,并解释输出序列。

本节把季节性"剥掉"用于下游分析。读完后你能解释各国统计局公布的"CPI 同比"是怎么来的,以及为什么业务上的同比分析要先做季节性调整。

一、为什么要"调整":让"今年 8 月 vs 去年 8 月"可比

假设某电商今年 8 月销量 1.2 亿元,去年 8 月 1 亿元。表面看增长 20%。但 8 月本来就有"暑期消费高峰"——8 月销量比 6 月高 25% 是季节性常态。如果不剥掉季节性,你说"今年 8 月比去年 8 月增长 20%",但其中多少是"今年真的增长",多少是"季节性模式没变"?

季节性调整后,调整后序列剔除了季节性"指纹",剩下的只是"今年 8 月相对去年 8 月的真实变化"——这才是同比分析真正想要的信号。各国统计局每月公布的"CPI 同比"、失业率、零售销售数据都做了季节性调整。

二、X-13ARIMA-SEATS 是什么

X-13ARIMA-SEATS 是一套由美国人口普查局和欧统局联合开发、用于季节性调整的工业级方法。它的工作流大致是:

  1. 预调整:识别日历效应(交易日差异、复活节位置、移动节假日)。
  2. 建模:用 RegARIMA 模型拟合"季节性 + 趋势 + 不规则项"三个成分。
  3. 分解:用 X-11 或 SEATS 算法从 RegARIMA 模型中分离出各成分。
  4. 诊断:检查季节性 / 不规则项的稳定性,给出可调节的诊断报告。

X-13 的优势:

  • 稳健:处理多种边缘情况(闰年、交易日差异、移动节假日)。
  • 可诊断:自带 M 检验、谱图、残差诊断。
  • 事实标准:各国统计机构使用同一套方法,方法学透明度高。

三、用 statsmodels 跑 X-13 调整

import pandas as pd import numpy as np from statsmodels.tsa.x13 import x13_arima_analysis # 构造月度销量数据:趋势 + 12 月季节性 + 噪声 rng = np.random.default_rng(5) n_months = 60 monthly_seasonal = 20 * np.sin(2 * np.pi * np.arange(n_months) / 12) trend = np.linspace(100, 300, n_months) y = trend + monthly_seasonal + rng.normal(0, 5, n_months) y = pd.Series(y, index=pd.date_range("2019-01-01", periods=n_months, freq="MS")) # 跑 X-13 调整(需要系统安装 X-13ARIMA-SEATS 程序) result = x13_arima_analysis(y, x12path="x13as") # x12path 指向 X-13 可执行文件 adjusted = result.seasadj # 季节性调整后序列 trend_component = result.trend irregular = result.irregular

result.seasadj 就是把季节性剥掉后的序列。把原序列和调整后序列画在一张图上:

import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(10, 4)) ax.plot(y.index, y.values, label="原序列") ax.plot(adjusted.index, adjusted.values, label="季节性调整后") ax.legend() plt.tight_layout()

调整后序列:

  • 季节性幅度被显著压平:原序列里"12 月高峰、2 月低谷"被平滑掉。
  • 趋势更清晰:调整后序列近似单调上升,便于看"今年相对去年的真实变化"。

四、X-13 vs 简单移动平均

工程上也有人用简单移动平均(如 12 月中心化 MA)做季节性调整。X-13 比简单 MA 强在三个地方:

维度 简单 MA X-13
交易日 / 移动节假日 忽略 显式建模
季节性变化 假设固定 允许缓慢变化
残差诊断 自带 M 检验、谱图、稳定性测试
工程门槛 极低 需要安装 X-13ARIMA-SEATS 程序

如果你的数据有强日历效应(财务月末、交易日差异、移动节假日),X-13 是更稳的选择。否则简单 MA 也够用。

五、调整后序列的下游应用

  • 同比 / 环比分析:调整后序列计算同比更能反映"真实业务变化"。
  • 回归建模:把调整后序列作为因变量,把宏观经济、促销活动作为自变量,回归系数更可解释。
  • 异常检测:调整后序列的"残差"反映了真正的异常事件(疫情、双 11、系统故障)。

⚠️ 常见坑:别在原序列上同时做趋势建模和季节性调整。如果你要做未来 6 个月的预测,应当对原序列拟合(让模型自己处理季节性);季节性调整主要是"分析过去",不是"预测未来"。

六、当 X-13 不可用时:用 STL 替代

X-13ARIMA-SEATS 需要单独安装程序(在 Linux 上是 x13as,Windows 上需要额外配置)。如果系统不便安装,可以用 seasonal_decompose 或 statsmodels 的 STL 做"够用"的季节性调整:

from statsmodels.tsa.seasonal import STL stl = STL(y, period=12, robust=True).fit() adjusted = y - stl.seasonal # 去掉季节性

STL 的优势是不依赖外部程序、纯 Python;劣势是处理移动节假日和交易日差异不如 X-13 精细。

七、一个完整案例:电商月度数据的季节性调整

我们用 6.5 年(78 个月)的合成电商销量数据演示一次完整流程:

n = 78 monthly = 30 * np.sin(2 * np.pi * np.arange(n) / 12) trend = np.linspace(200, 600, n) y = trend + monthly + rng.normal(0, 8, n) y = pd.Series(y, index=pd.date_range("2018-01-01", periods=n, freq="MS")) # 简单 STL 季节性调整 stl = STL(y, period=12, robust=True).fit() adjusted = y - stl.seasonal # 对比:原序列"今年 8 月" vs "调整后今年 8 月" print("原序列 8 月销量均值:", y[y.index.month == 8].mean()) print("调整后 8 月销量均值:", adjusted[adjusted.index.month == 8].mean()) # 调整后 8 月销量应该接近趋势线(季节性被剥掉)

调整后,8 月的均值应当比原序列低 30 左右(剥掉夏季高峰),但月度的同比变化("今年 8 月 vs 去年 8 月")的差异变小、信号更清晰。

本节要点回顾

  • 季节性调整的目的:让同比 / 环比分析更准确,剥离季节性"指纹"。
  • X-13ARIMA-SEATS:工业级标准,处理日历效应、移动节假日、季节性变化。
  • statsmodels 接口x13_arima_analysis,需要系统安装 X-13 程序。
  • 替代方案:STL 分解在 Python 环境下更易用,效果略弱但够用。
  • 应用边界:季节性调整主要用于"分析过去",不是"预测未来"——预测应让模型自己处理季节性。
  • 下一章线索:5 章专攻比季节性更难识别的周期性——长度不固定的长波。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U