☰
时间序列分析实战:分解、指数平滑与ARIMA模型选择与避坑指南
2026/10/14 6:29:44 网站建设 项目流程

简介:这份资源面向数据分析初学者与需要处理时序数据的从业者,系统梳理时间序列分析的三类主流方法:分解、指数平滑与ARIMA模型,并配套Excel、Matlab、SPSS三种统计软件的操作素材,帮助读者在真实数据上理解趋势、季节性与预测建模的完整流程。压缩包共55个文件,约967KB,以32个m脚本、17个xlsx与2个xls数据表为主,另有read-me说明、docx项目文档与md索引,脚本可直接在Matlab中运行,表格覆盖香槟销量、比利时与西德GDP等经典案例,便于对照练习。内容预览显示素材按分解、平滑、趋势估计与预测项目分模块组织,包含Holt、Holt-Winters、广义指数平滑及Gompertz、Logistic等模型实现,并附MAPE误差评估脚本,可帮助读者从数据读取、建模到精度比较形成闭环。目前已有64人学习下载,适合作为课程作业、项目复现与自学练手的参考材料。

1. 时间序列分析的三板斧:分解、指数平滑与 ARIMA 到底该先动哪个

拿到一份带时间戳的销售流水、设备振动记录或者气象观测数据,第一反应往往是画条折线看看趋势。但真正要预测下一周、下一月甚至下一季度的数值时,光靠肉眼外推迟早翻车。时间序列分析里最常被同时提起的三类方法——分解、指数平滑、ARIMA 模型——其实对应三种完全不同的假设:分解认为序列由趋势、季节和随机项叠加而成;指数平滑认为近期观测比远期观测更重要;ARIMA 则认为序列的当前值可以由自身的历史值和历史误差线性表出。Excel、Matlab、SPSS 这三个统计软件各自擅长其中某一段流程,选错工具或者跳过平稳性检验直接套 ARIMA,是新手最容易踩的坑。这篇笔记按“先判断序列结构,再选模型,最后落地验证”的顺序,把三条路径的操作细节和参数边界讲清楚,适合手里有数据、需要尽快产出可解释预测结果的从业者。

2. 序列分解:把趋势和季节从噪声里剥出来

2.1 分解的两种模型:加法与乘法怎么选

时间序列分解的核心是把观测值 ( Y_t ) 拆成趋势项 ( T_t )、季节项 ( S_t ) 和随机项 ( R_t )。加法模型写作 ( Y_t = T_t + S_t + R_t ),乘法模型写作 ( Y_t = T_t \times S_t \times R_t )。选哪个不靠猜,看季节波动的幅度是否随趋势水平变化。如果某产品销量逐年增长,且每年旺季与淡季的差值绝对值也在扩大,用乘法;如果季节波动的绝对值常年稳定在某个区间,用加法。Excel 里没有直接的分解菜单,常见做法是用移动平均求趋势,再用原序列减去趋势得到去趋势序列,最后按月份或季度求平均得到季节指数。Matlab 的decompose函数和 SPSS 的“分析→预测→季节性分解”都支持两种模型,但 SPSS 默认输出四个新变量:误差、季节调整后序列、平滑趋势和季节因子,初次使用容易把“季节调整后序列”误当成预测值。

2.2 用 Matlab 做一次完整的加法分解

下面这段代码对一个模拟的月度销售序列做加法分解,并画出四个成分。数据用正弦波叠加线性趋势和随机噪声生成,方便复现。

% 生成模拟月度销售数据:36个月,线性趋势+年度季节+噪声 t = (1:36)'; trend = 100 + 2.5*t; % 线性增长趋势 season = 15*sin(2*pi*t/12); % 周期为12的季节项 noise = 5*randn(36,1); % 随机噪声 y = trend + season + noise; % 加法模型合成 % 用移动平均做分解,窗口设为12 trend_est = movmean(y, 12); % 12期移动平均估计趋势 detrended = y - trend_est; % 去趋势 season_est = zeros(12,1); for m = 1:12 season_est(m) = mean(detrended(m:12:end)); % 按月份求平均 end season_est = season_est - mean(season_est); % 季节项均值为零 season_full = repmat(season_est, 3, 1); % 扩展到36个月 resid = y - trend_est - season_full; % 残差 % 绘图 figure; subplot(4,1,1); plot(y); title('原始序列'); subplot(4,1,2); plot(trend_est); title('趋势项'); subplot(4,1,3); plot(season_full); title('季节项'); subplot(4,1,4); plot(resid); title('残差项');

这段代码的关键参数是移动平均窗口12,对应年度周期。如果数据是季度数据,窗口改成4;如果是周数据且存在年度周期,窗口改成52。movmean在序列两端会产生缺失值,Matlab 默认用可用数据计算,但两端趋势估计偏差较大,做正式预测时通常只使用中间段的趋势。残差项如果还能看出规律,说明分解不充分,需要检查是否漏掉了周期更长的成分或者异常值。

2.3 SPSS 季节性分解的输出解读与陷阱

SPSS 的“季节性分解”过程会生成四个变量:ERR(残差)、SAS(季节调整后序列)、SAF(季节因子)、STC(平滑趋势)。很多人直接把 SAS 当作预测结果,这是错的。SAS 只是去掉了季节项,趋势和随机项还在里面。正确的用法是:用 STC 外推趋势,用 SAF 的周期模式外推季节,两者相加或相乘得到预测。SPSS 输出里还有一个容易忽略的细节:季节因子默认是围绕 1 的乘法形式,如果原始数据做过对数变换,季节因子要取指数还原。另外,SPSS 对缺失值的处理是整行删除,如果序列中间有断点,分解结果会整体偏移,建议先在 Excel 里补齐或插值。

3. 指数平滑:从简单平滑到 Holt-Winters 的落地参数

3.1 一次、二次、三次平滑分别对应什么数据形态

指数平滑家族按平滑次数和是否含季节项分几种。一次指数平滑适合没有趋势和季节的平稳序列,公式是 ( \hat{y}_{t+1} = \alpha y_t + (1-\alpha)\hat{y}_t ),其中 ( \alpha ) 是平滑系数,越接近 1 越看重近期观测。二次指数平滑(Holt 线性趋势)在平滑基础上增加趋势项,适合有线性趋势但无季节的序列。三次指数平滑(Holt-Winters)再增加季节项,分加法季节和乘法季节两种。Excel 的“预测工作表”底层用的就是 Holt-Winters,但界面只暴露“季节性”一个选项,自动判断加法和乘法,遇到强趋势加弱季节的数据经常选错。Matlab 的exponentialSmoothing对象可以显式指定'additive'或'multiplicative',SPSS 的“指数平滑”过程则要求用户先选模型类型再设参数。

3.2 用 Excel 预测工作表跑 Holt-Winters 并手动校核

Excel 2016 之后的版本在“数据”选项卡下有“预测工作表”,操作路径短,但参数藏在“选项”里。以下步骤针对一个月度销售表,A 列是日期,B 列是销量。

第一步,选中 A 列和 B 列的数据区域,点击“数据→预测工作表”。第二步,在“创建预测工作表”对话框里,图表范围会自动扩展,把“预测结束”设为当前数据末尾往后 6 个月。第三步,点开“选项”,把“置信区间”设为 95%,勾选“包含预测统计信息”。第四步,在“季节性”下拉里,如果序列的波动幅度随趋势增大,选“自动检测”往往不够,手动指定“乘法”更稳。第五步,点“创建”,Excel 会生成一个新工作表,包含预测值、置信区间上下限和一组统计指标。

生成后不要直接交差。检查新工作表里的MASE(平均绝对缩放误差)和SMAPE(对称平均绝对百分比误差)。MASE 小于 1 说明预测比朴素法好,大于 1 说明还不如直接用上一期值。如果 MASE 偏高,回到“选项”里把“平滑系数”从自动改为手动,Alpha 设 0.2 到 0.4 之间试几次,Beta 和 Gamma 通常设 0.1 到 0.3。Excel 的预测工作表不显示平滑系数,但可以通过“预测统计信息”里的Alpha、Beta、Gamma估计值反推。

3.3 Matlab 里 Holt-Winters 的参数边界与初始值问题

Matlab 的exponentialSmoothing函数对初始值和参数估计更透明,但也更容易因为初始值设错导致优化不收敛。

% 假设 y 是月度销量列向量,周期为12 y = load('sales_data.mat'); % 替换为实际数据加载 model = exponentialSmoothing(y, 'additive', 'additive'); model.Alpha = 0.3; % 水平平滑系数 model.Beta = 0.1; % 趋势平滑系数 model.Gamma = 0.2; % 季节平滑系数 model.InitialLevel = mean(y(1:12)); % 初始水平取第一年均值 model.InitialTrend = (mean(y(13:24)) - mean(y(1:12)))/12; % 初始趋势 model.InitialSeason = y(1:12) - mean(y(1:12)); % 初始季节 fit(model, y, 'Estimate'); forecast_values = forecast(model, 6);

这段代码里InitialLevel、InitialTrend、InitialSeason如果不显式指定,Matlab 会用前几个周期做粗略估计,遇到开头有异常值的数据就会把初始季节项带偏。Estimate选项会让 Matlab 用最大似然重新估计 Alpha、Beta、Gamma,但不会重新估计初始值,所以初始值仍需人工检查。forecast(model, 6)返回未来 6 期预测,置信区间用forecast(model, 6, 'Y0', y)获取。如果优化过程中出现“无法收敛”警告,先把 Gamma 固定为 0,退化成 Holt 线性趋势模型,确认趋势项合理后再加回季节项。

4. ARIMA 模型:平稳性、定阶与残差诊断的完整链路

4.1 平稳性检验:ADF 和 KPSS 要对着看

ARIMA 的前提是序列平稳,或者通过差分后平稳。单位根检验里 ADF 的原假设是“存在单位根”,p 值小于 0.05 才拒绝原假设、认为平稳。KPSS 的原假设相反,是“序列平稳”,p 值大于 0.05 才不拒绝平稳。两个检验对着看能减少误判:ADF 通过但 KPSS 拒绝,说明序列可能带确定性趋势;ADF 不通过但 KPSS 不拒绝,说明检验功效不足,需要增加滞后阶数或换更长序列。Matlab 的adftest和kpsstest都支持指定滞后阶数,默认用 AIC 选阶,但月度数据建议手动设'Lags', 12以覆盖年度周期。

4.2 用 SPSS 做 ARIMA 定阶:ACF 与 PACF 的读图规则

SPSS 的“分析→预测→创建传统模型→ARIMA”路径里,定阶靠自相关图(ACF)和偏自相关图(PACF)。规则是:AR(p) 的 PACF 在 p 阶后截尾,ACF 拖尾;MA(q) 的 ACF 在 q 阶后截尾,PACF 拖尾;ARMA(p,q) 两者都拖尾。实际操作中,月度数据先看 ACF 在 12、24 阶是否有显著尖峰,有则考虑季节差分或加季节 MA 项。SPSS 输出里 ACF 和 PACF 的置信区间默认是 95%,超出区间的尖峰才算显著。一个常见错误是看到 ACF 第一个尖峰就定 MA(1),忽略了后面 12 阶的尖峰,结果模型残差在季节周期上仍有自相关。定阶后看“模型统计”里的平稳 R 方和Ljung-Box Q统计量,Q 的 p 值大于 0.05 说明残差没有明显自相关,模型可用。

4.3 Matlab 里 ARIMA 的估计、预测与残差白噪声检验

Matlab 用arima函数构建模型,estimate估计参数,forecast预测,infer取残差。

% 假设 y 是经过一阶差分和季节差分后的平稳序列 y = diff(diff(sales_data, 1), 12); % 先1阶差分,再12步季节差分 model = arima('ARLags', 1, 'MALags', 1, 'D', 0, 'Seasonality', 12, ... 'SARLags', 1, 'SMALags', 1); fit = estimate(model, y); resid = infer(fit, y); % 残差白噪声检验 [h, p] = lbqtest(resid, 'Lags', 20); if h == 0 disp('残差通过白噪声检验'); else disp('残差仍有自相关,需重新定阶'); end % 预测未来6期 [forecast_y, forecast_mse] = forecast(fit, 6, 'Y0', y);

ARLags和MALags指定非季节项的阶数,SARLags和SMALags指定季节项的阶数,Seasonality设为 12 表示月度周期。D设为 0 是因为前面已经手动做了差分,如果让arima自动差分,D设 1、Seasonality设 12 时会自动做季节差分。lbqtest的Lags一般取 20 或 2 倍周期,p 值大于 0.05 才通过。forecast的Y0参数传入原始平稳序列,返回的forecast_mse是预测方差,开方后得到标准误,用来构造置信区间。

5. 避坑与排查:时间序列分析里最容易翻车的五个地方

5.1 现象:分解后季节项每年都一样,预测却对不上

原因:加法分解假设季节项不随趋势变化,但实际数据里季节波动幅度在增大。解决:改用乘法分解,或者在分解前对数据做对数变换,把乘法关系转成加法关系再分解。

5.2 现象:指数平滑的 MASE 小于 1,但预测值明显偏高

原因:Excel 预测工作表自动选择的平滑系数偏向近期观测,遇到序列末尾有异常高值时会把异常当成趋势。解决:手动把 Alpha 调低到 0.2 以下,或者先在原始数据里把末尾异常值替换为移动中位数,再重新预测。

5.3 现象:ARIMA 模型 AIC 很小,但预测几期后迅速发散

原因:差分次数过多导致过差分,序列变得过度平稳,模型把噪声也当成信号拟合。解决:检查差分后的序列方差,如果差分后方差反而比差分前大,说明过差分,减少差分次数。用 ADF 和 KPSS 对着看,两个都通过才做下一步。

5.4 现象:SPSS 季节性分解输出的季节因子全是 1

原因:数据长度不足两个完整周期,SPSS 无法估计季节项,默认输出 1。解决:确认数据至少覆盖两个完整周期,月度数据至少 24 个月,季度数据至少 8 个季度。不足时改用指数平滑的 Holt 线性趋势模型,不加季节项。

5.5 现象:Matlab 的estimate报“无法收敛”

原因:初始值离真实值太远,或者模型阶数过高导致参数冗余。解决:先固定部分参数,比如把Gamma设为 0 退化成 Holt 模型,估计出 Alpha 和 Beta 后再加回季节项。也可以把ARLags和MALags从高阶降到 1 阶,逐步增加。

6. 三条路径的交叉验证与一个实用技巧

三条路径不是互斥的。分解能帮你理解序列结构,指数平滑适合快速产出基准预测,ARIMA 在残差诊断通过时往往给出更窄的置信区间。我一般会先用分解看趋势和季节的强度,如果季节项占方差比例超过 30%,优先用 Holt-Winters;如果趋势占主导且季节不明显,用 Holt 线性趋势;如果分解后残差还有明显自相关,再上 ARIMA。交叉验证的做法是:把序列末尾 6 期留作测试集,分别用三种方法预测,比较 MASE 和 RMSE。MASE 对尺度不敏感,适合不同量纲的序列对比;RMSE 对异常值敏感,能暴露模型在极端点上的表现。

一个实用技巧是“滚动原点预测”。不要只做一次留出法,而是从序列中间开始,每次向前滚动一期,重新估计参数并预测下一期,累计得到多组预测误差。Matlab 里可以用for循环实现:

n = length(y); errors = zeros(n-24, 1); for i = 24:n-1 train = y(1:i); test = y(i+1); model = arima('ARLags', 1, 'D', 1, 'Seasonality', 12, 'SARLags', 1); fit = estimate(model, train, 'Display', 'off'); pred = forecast(fit, 1, 'Y0', train); errors(i-23) = test - pred; end mase = mean(abs(errors)) / mean(abs(diff(y(1:24))));

这段代码从第 24 期开始滚动,每次用历史数据重新估计 ARIMA 并预测下一期。mase的分母用训练集前 24 期的一阶差分平均绝对值,这是 MASE 的标准定义。滚动原点预测比单次留出法更耗时间,但能看出模型在不同时间段的稳定性。如果errors的方差在某个时间段突然变大,说明模型对结构变化不鲁棒,需要检查那段时间是否有促销、政策或设备故障等外部事件。

我自己的习惯是:任何时间序列模型跑完,先看残差图,再看滚动误差,最后才看预测值。残差图里如果还有规律,预测值再漂亮也是玄学。滚动误差如果随时间放大,说明模型只拟合了历史,没抓住生成机制。这两关过了,预测值才值得写进报告。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询