2026/10/3 14:26:45

MATLAB零售数据季节ARIMA预测:从定阶到诊断的完整流程

MATLAB零售数据季节ARIMA预测:从定阶到诊断的完整流程 直接说结论这个案例我跑了很多遍也帮别人排查过不少类似问题。最终你会发现月度销量数据能不能用ARIMA关键在于你愿不愿意先花十分钟把周期性这回事看清楚而不是急着把数据丢进命令窗口。这篇就用MATLAB自带的零售销售数据完整走一遍季节销量预测流程。数据自带明显的月度周期性几乎是给ARIMA模型量身定做的练习场。适合已经啃过ARIMA基础概念、但不知道在实际数据上怎么定阶、怎么诊断、怎么预测的读者。整篇没有绕弯子代码直接给理由也直接讲。我能保证的是你按这个流程下来至少能跑出一个可解释、可复现、可评估的季节ARIMA模型而不是只会调用一次arima黑盒。1. 这个案例为什么值得折腾零售数据的季节结构拆解1.1 Data_Retail 到底长什么样MATLAB里这份零售数据是通过load Data_Retail加载的它是Econometrics Toolbox自带的示例数据集官方文档在讲季节ARIMA时也常拿它当样本。很多版本里这个数据叫Data是一列按月采样的零售额时间跨度通常覆盖十几年。不同版本的工具箱在具体年份范围上可能有细微差异这不影响我们分析因为核心特征是稳定的整体上行趋势、明显的一年12个月周期、局部毛刺噪声。我第一次拿到这份数据时第一件事不是建模而是先画图。你运行下面这段代码就能看到我最开始看到的画面clear; clc; load Data_Retail; y Data(:); % 确保是列向量有些版本加载后是行向量 T length(y); figure; plot(y); xlabel(月度序号); ylabel(零售额); title(MATLAB自带零售销售数据原始序列);Data(:)这一步是个小细节很多教程会默认数据已经是列向量但实际加载出来的形状在不同版本里不一定一致。加上(:)之后不管它是行还是列都变成一列后面所有操作都不会因为维度问题报错。从图里能立刻看到三个特征第一整体往上走这是趋势第二每年有规律的高低起伏这是季节第三细节上有一些不规则的抖动这是噪声。零售额这种数据天然就是三重结构的叠加而ARIMA要做的事情就是把前两样尽量抓干净剩下来的随机部分才交给误差项去解释。1.2 把销量序列拆成趋势、周期和噪声三件事分析季节预测时我的习惯是把一个序列在心里拆成三层趋势层、周期层、噪声层。趋势层是长期方向比如整体经济规模扩大带动的销量上涨周期层是固定频率的重复模式比如每年年末的消费高峰、年初的回调噪声层是那些没法用规律解释的随机扰动比如某月促销活动意外爆量、天气异常导致到店人数变化。这三层对建模的启示完全不同。趋势层可以用差分来处理周期层需要周期性差分或者季节项噪声层只能通过残差诊断去确认它是不是真的随机。如果你不拆开看直接上手拟合模型很容易把趋势和周期混在一起最终预测出来的东西既不像趋势也不像周期。零售数据最友好的一点在于它的周期几乎严格压在12这个数字上。这意味着月度周期模型里滞后12、24、36这些位置会反复出现相关信息。有些行业数据周期是季度变化有些是每周变化周期长度不一定是整数月那处理起来就麻烦得多。所以我说这份数据适合拿来折腾ARIMA模型不是客套话。1.3 普通ARIMA的短板季节性差分要做什么基础ARIMA(p,d,q)里面的d阶差分处理的是趋势。比如d1就是对序列做一阶差分把原本带有漂移的序列变成围绕某个水平波动的序列。但月度零售数据的问题在于即便你做完一阶差分第12个滞后位置上仍然会残留显著的正自相关。这是因为一年的周期模式没有被消除它只是被平移了一下结构还在。这时候就需要季节性差分的介入。用数学算子的语言说普通一阶差分是(1-B)季节差分就是(1-B^12)。季节ARIMA实际上是同时用两个算子(1-B)^d负责消除非季节趋势(1-B^12)^D负责消除年度周期。对应的完整形式写作ARIMA(p,d,q)(P,D,Q)^12。在这个案例里我们大概率需要d1消除趋势和D1消除年度周期。你如果不做季节差分ACF图会在滞后12、24、36处拖着一条长长的尾巴模型预测区间会越来越大最后基本失去参考意义。2. 开工前的数据体检加载、可视化与平稳性判断2.1 为什么要先给销量取个对数跑时间序列模型之前有一个常见的预处理操作对原始序列取对数。零售额这类数据往往存在一个特点——水平越高的时候波动幅度也越大。比如销售额100万的时候上下波动可能是几万销售额涨到1000万的时候波动可能变成几十万。这种方差随水平变化的现象会让模型残差不满足同方差假设影响预测区间的可靠性。取对数之后乘法波动会变成加法波动直观表现是曲线振幅在不同水平段上变得相对均匀。更重要的一个好处是如果原始数据里的季节模式是乘法性的比如旺季销量是淡季的1.5倍取对数后这种乘法关系就转化成加法关系正好落入ARIMA这种线性建模的框架内。官方文档在演示这个数据集时也是先取对数再建模这不是偶然。ylog log(y); figure; subplot(2,1,1); plot(y); title(原始零售额); subplot(2,1,2); plot(ylog); title(对数零售额);对比两个图你会发现对数序列的上升趋势更接近一条直线波动规律更干净。后面所有建模都在ylog上进行预测完成后用exp还原回原始销量尺度。2.2 ADF检验与目视检查平稳性不是过个p值就完事判断平稳性教科书上会教你用ADF检验MATLAB里就是adftest这个函数。实测经验是不要只跑一次默认参数至少要把模型形式设置为含趋势的TS因为零售数据本身带着明显趋势用不含趋势的默认设置很容易得出错误结论。[h0, p0] adftest(ylog, model, TS); [h1, p1] adftest(diff(ylog, 1), model, TS); [h12, p12] adftest(diff(diff(ylog, 1), 12), model, TS); fprintf(原始序列h%d, p%.4f\n, h0, p0); fprintf(一阶差分h%d, p%.4f\n, h1, p1); fprintf(一阶差分季节差分h%d, p%.4f\n, h12, p12);一般来说h00表示原始序列有单位根不平稳h11表示一阶差分后平稳h121表示经过季节差分后依然平稳。这里有个关键提醒ADF检验的p值受滞后阶数选择、样本长度的影响很大同一组数据换个默认参数结论可能就变了。所以ADF只是参考最终判断一定要配合ACF图和时序图一起看。我的习惯是检验通过了我会再去画图看有没有明显的趋势残留检验没通过我也会去看看是不是数据里有孤立尖峰在干扰检验。不要做一个盲信p值的人。2.3 d和D的直觉一阶差分清趋势十二阶差分清周期对比下面两种差分结果的走势可以帮助你建立直觉figure; subplot(2,1,1); plot(diff(ylog, 1)); title(一阶差分后的序列); subplot(2,1,2); plot(diff(diff(ylog, 1), 12)); title(再做12阶季节差分后的序列);一阶差分后序列不再持续上涨但你依然能看到明显的年度起伏每年同一位置出现类似的波峰或波谷这就是季节性残留。再做12阶季节差分后序列就变得比较碎没有规律的年度大波浪了。这种情况对应d1、D1。有些教程会建议先季节差分再判断是否需要一阶差分两种顺序在大部分数据集上结果一致。如果你发现做完季节差分后序列还有明显漂移再补一阶差分如果补了一阶差分后周期还在再回头加强季节差分。这个循环试错过程不丢人ARIMA定阶本来就是一个结合统计检验和图形判断的迭代过程。3. 从ACF/PACF推敲季节ARIMA的阶数3.1 在MATLAB里把ACF/PACF画出来怎么读定阶的核心工具是自相关函数ACF和偏自相关函数PACF。对差分完成后的序列直接调用MATLAB的autocorr和parcorr就能画出带置信边界的图形。d1 diff(ylog, 1); % 一阶差分 sd diff(d1, 12); % 季节差分 figure; autocorr(sd); title(季节差分后序列的ACF); figure; parcorr(sd); title(季节差分后序列的PACF);读图时重点关注两类位置。第一类是滞后1到3这些非季节位置它们决定模型里的AR和MA部分。第二类是滞后12、24、36这些季节位置它们决定SAR和SMA部分。一个常用的判读规则是如果ACF在滞后1处显著不为0之后快速截尾倾向于MA(1)如果PACF在滞后1处显著不为0之后快速截尾倾向于AR(1)如果ACF在滞后12处显著不为0且滞后24处衰减倾向于加一个SMA(1)如果PACF在滞后12处显著不为0且滞后24处衰减倾向于加一个SAR(1)如果ACF和PACF都在滞后12处显著一般选一个方向先试不要两个季节项同时都加。看ACF/PACF时还要克制一点图形里有5%的棒本来就会超出置信线不要看到一两个孤立尖峰就急着加阶数。真正的模式应该是多个连续滞后位置上呈现衰减或截尾的规律。3.2 候选模型与AIC/BIC用数字代替感觉肉眼判断有主观性所以我会再跑一组候选模型的AIC/BIC比较用数字辅助决策。AIC和BIC都是拟合优度参数惩罚的权衡值越小说明模型在解释力和简洁性之间平衡得越好。cand { {ARLags, 1, SARLags, 1}, ... {MALags, 1, SMALags, 1}, ... {ARLags, 1, SARLags, 1, SMALags, 1}, ... {MALags, 1, SARLags, 1, SMALags, 1}, ... {ARLags, [1 2], SARLags, 1}, ... {ARLags, 1, SARLags, [1 2]} }; for i 1:length(cand) Mdl arima(Constant, 0, D, 1, Seasonality, 12, cand{i}{:}); [EstMdl, ~, logL] estimate(Mdl, ylog, Display, off); [aic(i), bic(i)] aicbic(logL, EstMdl.NumParameters, numel(ylog)); end compTable table(aic, bic, VariableNames, {AIC, BIC}); disp(compTable);这里我用了arima里Seasonality12配合D1来表示季节差分。候选集合控制在非季节和季节阶数都不超过2的范围内因为月度季节模型一旦参数堆多了估计结果会很不稳定。需要说明的是AIC/BIC比较应当限定在相同差分阶数的模型之间。不同d或D下对数似然对应的样本数不一样直接比较数值没有意义。3.3 我最终常用的组合与不追求完美的理由在零售月度数据上有两组模型的出镜率特别高模型组合适用场景参数数量稳定性ARIMA(1,1,0)(1,1,1)^12季节因素以MA形式为主趋势由AR吸收较少很稳ARIMA(0,1,1)(0,1,1)^12经典航空模型推广到月度周期较少极其常见ARIMA(1,1,0)(1,1,0)^12季节因素也表现为AR形式少容易理解我自己在这个数据集上通常会在(1,1,0)(1,1,1)^12和(0,1,1)(0,1,1)^12之间做选择具体看ACF图更像哪种形式。如果你跑出来的AIC最低模型是别的组合不用慌只要差分阶数合理、残差诊断通过、预测结果稳定这个选择就是可用的。记住一件事时间序列建模的目标不是找到唯一正确模型而是找到一个对当前任务足够好、参数不过多、解释起来不绕的模型。别为了把某个AIC值降低零点几硬塞一个参数多一倍的模型进去。4. MATLAB里跑通全流程拟合、诊断、预测一次到位4.1 模型定义与estimate的完整代码选好组合后就到了真正建模的环节。以ARIMA(1,1,0)(1,1,1)^12为例完整代码是这样Mdl arima(Constant, 0, D, 1, Seasonality, 12, ... ARLags, 1, SARLags, 1, SMALags, 1); EstMdl estimate(Mdl, ylog);逐行解释Constant, 0差分后序列均值接近0不估计常数项。如果保留常数模型会多一个漂移项反而容易和差分结构冲突。D, 1做一阶非季节差分。Seasonality, 12周期长度是12配合D使用。在MATLAB里Seasonality12本身就会引入(1-B^12)的季节差分算子D控制季节差分的阶数。ARLags, 1非季节AR部分取1阶即AR(1)。SARLags, 1季节AR部分取1阶即SAR(1)。SMALags, 1季节MA部分取1阶即SMA(1)。estimate运行完成后窗口会输出每个系数的估计值、标准差、t统计量和p值。我一般会快速扫一眼参数显著性如果某个参数的p值很大且标准差比估计值还大说明这个参数基本识别不出来模型可能需要简化。4.2 残差诊断的正确姿势拟合完之后不能直接拿去预测先做残差诊断。这一步的目的是确认模型已经把数据里的规律榨干了剩下的东西基本是白噪声。res infer(EstMdl, ylog); figure; autocorr(res, NumLags, 30); title(模型残差的ACF); [h, pVal] lbqtest(res, Lags, [5 10 15 20]); disp(pVal);看残差ACF时如果所有滞后的自相关都落在置信边界内说明没有明显残留相关。lbqtestLjung-Box检验则给出一个更综合的判断p值全部大于0.05代表没有足够证据拒绝残差无自相关的原假设。这里有个经验之谈不要只盯着p值。p值只是没有发现显著的线性自相关不等于残差就绝对干净。我还会看一眼残差图本身确认残差随机分布在零轴两侧没有呈现某种喇叭口或者大段同号聚集。如果残差在某段时间连续为正、某段时间连续为负即便Ljung-Box检验通过了也说明可能遗漏了结构性断点或外生变量影响。另外一个小坑infer默认使用模型初值从无条件均值附近开始计算如果你发现残差最前面少数几个点异常大不用太紧张可以先忽略头部几个点再诊断。如果模型合理中间部分的残差模式才是重点。4.3 预测出来别急着用先做反变换拟合和诊断都通过后就可以对未来做预测。这里有一个最容易翻车的地方预测结果是在对数空间里的必须用exp还原成原始销量。numSteps 12; [yforLog, yciLog] forecast(EstMdl, numSteps, Y0, ylog); yfor exp(yforLog); yci exp(yciLog); figure; plot(1:T, exp(ylog), k); hold on; plot((T1):(TnumSteps), yfor, r-o, LineWidth, 1.5); plot((T1):(TnumSteps), yci, b--); xlabel(月度序号); ylabel(零售额); legend(历史数据, 预测值, 95%预测区间, Location, northwest); title(季节ARIMA预测结果);forecast的第三个输出yci是预测区间同样是在对数尺度上算出来的使用前也要exp。如果你忘了反变换图表上的数值可能只是零点几的小数和真实的百万级零售额完全对不上整个预测结果就失去了业务含义。画预测图时我的习惯是同时给预测区间不要只画一条点预测线。因为ARIMA不只是告诉你未来大概多少它还告诉你这个估计有多不确定。区间快速变宽往往意味着模型对未来数月的不确定性在累积这是正常的但要确保它不是毫无预兆地发散到不可用。5. 我的排错笔记收敛失败、阶数误判、预测发散的典型处理5.1 estimate卡住或参数爆炸时先别急着加阶数实际建模时estimate有时会输出一大段Optimization terminated之类的警告或者估计出的参数标准差大得离谱。我遇到这种情况的第一反应不是去调优化算法而是怀疑模型太复杂了。我给你讲过一条经验月度季节模型里如果非季节和季节部分各自都堆了2阶以上参数之间的共线性会非常严重。比如同时有SAR(1)、SAR(2)两个参数很难被数据区分开估计过程就会在参数空间里反复打转最后给你一个标准差爆炸的结果。处理方式按顺序尝试降低滞后阶数比如SAR从2阶降为1阶去掉AR部分或MA部分中不显著的项如果可以确定模型形式给estimate传X0初值。先用默认设置跑一次把输出中各参数的估计顺序记下来再看情况赋值能明显减少收敛到坏解的概率。EstMdl estimate(Mdl, ylog, X0, [0.5 0.5 0.5]);但要注意X0里的参数顺序必须和模型内部参数顺序一致。不确定顺序时建议先不带X0跑一次观察输出结果里的参数排列之后再决定要不要手动赋初值。不要盲写。5.2 定阶判断的两个常见误区误区一看到ACF和PACF在滞后12处都显著就同时加SAR和SMA。这两个项在模型里很容易相互抵消导致参数不可识别。更合理的做法是看哪个图在滞后12处更像截尾选一个方向加。如果实在难以判断就分别建两个模型用AIC比较而不是把两个季节项硬塞进同一个模型。误区二在不同差分阶数的模型之间比较AIC/BIC。差分会减少实际可用的观测数对数似然对应的样本量不同直接比数值就像拿不同长度的尺子量同一块地。比较一定要限定在同样的d和D组合下只调整AR/MA/SAR/SMA的阶数。这两条是我在帮别人看模型时最常抓到的问题十次有七次都栽在这上面。5.3 预测结果长成一条直线或爆炸曲线时怎么排查如果你发现预测值是条几乎水平的直线或者预测区间宽得离谱按顺序排查下面几件事是否忘了还原对数尺度。对数空间里看着很窄的区间还原完后可能是乘以几倍的误差不要被对数尺度的假象骗了。模型是否过度差分。差分次数过多会把有用的信号也删掉预测自然会被拉向一个平均水平丧失趋势和季节形态。AR参数是否接近1。接近单位根的AR系数会让预测长期趋于历史均值或者缓慢发散当参数估计值超过0.9时要警惕。季节周期是否真的是12。有些数据虽然看起来是月度但业务里的年可能遵循13个结算周期或者53周之类的特殊口径。我自己的习惯是先画一个periodogram看看主周期落在哪里再做定阶避免在错误周期上浪费大量调试时间。预测区间快速发散不完全等于模型错了。ARIMA本质上是一个外推模型预测步数越远不确定性累积越多。但如果第3步就已经发散到不可用大概率还是模型结构有问题回到第5.1节去简化模型。6. 预测效果评估与后续扩展6.1 把最后一年砍掉做回测RMSE与MAPE模型好不好不能只看拟合期画出来的曲线有多贴合。更严格的检验方法是把最后12个月的数据先藏起来只用前面的数据建模预测然后把预测值和真实值对比。这个过程叫回测也叫样本外评估。h 12; ytrain ylog(1:end-h); ytest ylog(end-h1:end); MdlTr arima(Constant, 0, D, 1, Seasonality, 12, ... ARLags, 1, SARLags, 1, SMALags, 1); EstMdlTr estimate(MdlTr, ytrain, Display, off); [yhatLog, ~] forecast(EstMdlTr, h, Y0, ytrain); yhat exp(yhatLog); ytrue exp(ytest); rmse sqrt(mean((ytrue - yhat).^2)); mape mean(abs((ytrue - yhat) ./ ytrue)) * 100; fprintf(RMSE: %.2f\n, rmse); fprintf(MAPE: %.2f%%\n, mape);RMSE对较大误差更敏感适合观察模型会不会在一些月份离谱地偏差MAPE是百分比误差方便和业务沟通平均偏差大概几个点。对零售月度数据来说MAPE在个位数到十几个百分点之间都算常见具体取决于数据本身的波动幅度。回测还可以做得更细不只固定一个测试窗口而是滚动多个起点每次多往前预测一步或一个季度最后把所有预测误差汇总。这样做能更真实地反映模型在实际滚动预测中的表现也更容易发现某个特定月份的系统性偏差。6.2 下一步可以玩的花样当基础SARIMA跑稳了还想继续往上做可以考虑几个方向第一引入外生变量。用regARIMA可以加入节假日、促销力度、价格指数等信息把你知道下个月会发生什么的因素从纯随机误差里剥离出来。这对零售场景特别有用因为消费节奏很多时候受活动安排驱动纯粹靠历史周期预测会漏掉一次大促的影响。第二做多序列联合预测。如果手里有多个品类或多个门店的销量可以考虑varm或状态空间模型ssm让各序列之间共享信息尤其是季节模式相似的序列联合估计往往比单独建模更稳。第三用深度学习模型做对比。MATLAB的Deep Learning Toolbox可以搭LSTM或简单的时序网络把它和ARIMA放到同一份数据上做回测对比。我自己实测下来的体会是月度周期清晰的零售数据上只要SARIMA定阶到位它往往是极其难被击败的对手。深度学习只有在引入外生变量、处理复杂交互时才有明显优势不要盲信越高级越准。还有一个轻量替代方案在fitlm里加入12个周期虚拟变量或者傅里叶项再配合趋势项也能做成一个可解释的季节预测基线。适合你需要在几分钟内出一个可用模型、不想在ARIMA定阶上花时间的场景。最后分享一个我自己的习惯做完模型后把关键判断理由写下来——为什么d取1、为什么季节差分选12、为什么在SAR和SMA之间最终选了这一边。这些文字记录在三个月后回头看时比任何一个p值都有价值。预测这件事模型给的是基准线业务判断给的是偏移量ARIMA能把前一半稳稳做好就已经非常值钱了。