MATLAB零售数据ARIMA实战:从差分定阶到季节性预测
直接上代码。先说结论MATLAB自带的那份零售销售数据确实是拿来折腾ARIMA模型的好料子。它本身带着明显的月度周期数据粒度统一、时间跨度稳定、还带一点趋势起伏做季节性销量预测正好能把ARIMA从理论拉到实战。这篇文章我会老老实实把整个过程拆开讲一遍从数据长什么样、为什么要做季节差分到阶数怎么定、代码怎么写、预测结果怎么判最后再聊几个我实际踩过的坑。适合刚入门时间序列、手头有MATLAB但不知道从哪下手的同学也适合想搞明白ARIMA参数背后逻辑的兄弟。1. 数据与场景为什么这份零售数据适合练ARIMA1.1 数据集长什么样怎么加载MATLAB的Econometrics Toolbox示例数据里带着一份零售销售数据我这边用到的加载方式是这样% 加载MATLAB自带的零售销售数据集 load Data_RetailSales whos如果用的是较新版本加载后工作区会出现一个时间表或者包含销售数值和日期的结构体。大致字段就是时间戳和销售额。数据是按月统计的零售额时间跨度从某年1月一直排到某年12月中间没有断档这种连续月度数据对建模来说特别省心。我习惯先把字段名捋清楚然后转成统一的序列变量% 统一提取销售序列 retail Data_RetailSales; % 具体字段名以工作区为准 sales retail.RetailSales; % 如果字段叫别的改成对应字段 dates retail.Date; % 日期序列有时候加载出来是double矩阵有时候是timetable无所谓关键是拿到整齐的等间隔月度序列。等间隔这件事在时间序列建模里非常重要ARIMA模型默认把你喂进来的数据当成连续时间点处理一旦中间有空缺模型估计很容易出幺蛾子。1.2 先画图用眼睛判断趋势和周期加载完数据我从来不急着算指标第一件事永远是画图。这是最直观的一步很多问题在图上扫一眼就能看出来。figure; plot(dates, sales, LineWidth, 1.2); title(零售销售月度数据); xlabel(时间); ylabel(销售额); grid on;这张图通常能看到两个信号一个是整体走势在缓慢上行说明序列非平稳存在趋势成分另一个是每年同一个位置会出现明显的波峰波谷说明有稳定的月度季节性。拿这份数据举例年底附近通常冲高年初回落每年重复这个节奏。这种规律性非常强的序列恰好是ARIMA家族最能发挥的场景。1.3 为什么要用ARIMA而不是其他模型很多人会问数据都带周期了是不是用季节分解或者简单回归就行ARIMA强的地方在于它不把趋势和季节当成需要手动剥离的干扰项而是把它们建模进随机过程里。靠差分把非平稳成分消掉靠自回归和移动平均项把残留的时间依赖关系刻画出来本质上是“让数据自己解释自己”。再直白一点线性回归需要你手工构造季节哑变量、月份特征、滞后项ARIMA把这些东西通过p、d、q和季节项P、D、Q统一封装了。你不用提前告诉模型“1月通常低12月通常高”它自己能从历史序列里学出来。2. 平稳性判断与差分处理建模型前必须过的关2.1 什么是平稳性为什么ARIMA死磕这个ARIMA里的I也就是Integrated指的就是差分。差分的目的就是为了让序列变平稳。那什么叫平稳简单理解就是序列的统计性质不随时间变化——均值大致稳定方差不剧烈波动自相关结构只跟间隔有关。为什么ARIMA要求平稳因为AR和MA部分本质上是回归模型如果序列均值一直在漂你等于拿一个常数系数去拟一条一直在变化的曲线拟合结果自然站不住脚。判断平稳性最常用的就是单位根检验。MATLAB里直接有adftest[h, pValue] adftest(sales); disp(pValue);h 1意味着拒绝“存在单位根”的原假设也就是序列平稳h 0代表不平稳需要差分。实际操作中这份原始零售数据大概率是不平稳的因为趋势太明显了。2.2 差分阶数和季节差分怎么选先做普通差分d1 diff(sales); % 一阶差分 figure; plot(d1);一阶差分通常能把趋势抹平。但这个零售数据还有季节性一阶差分之后你会发现周期性依然存在只是幅度变了。这时候需要做季节差分间隔是12个月ds diff(d1, 12); % 在一阶差分基础上再做12步季节差分 figure; plot(ds);季节差分做完序列基本就变得“平静”了。这是不是说明d1, D1就是最佳选择不一定。经验上看这个数据集很可能是这个配置但更严谨的做法是不断尝试组合用后面提到的信息准则来定。建模过程中我自己有个心得能少差分就别多差分。差分虽然能平稳化但也会丢信息差分过度会导致预测方差变大、置信区间宽到没法看。所以在做差分前最好同时看一眼adftest的 p 值和差分后序列的样子不要机械执行“不平稳就再差分”的流程。3. 模型定阶从ACF/PACF到网格搜索3.1 看自相关图建立定阶直觉定阶是ARIMA最让人头疼的环节。第一步是看图说话figure; subplot(2,1,1); autocorr(ds); title(差分序列的自相关图 ACF); subplot(2,1,2); parcorr(ds); title(差分序列的偏自相关图 PACF);ACF看的是序列跟它自己滞后k步之间的相关程度PACF是剔除了中间滞后影响后的偏相关。经验法则很简单ACF拖尾、PACF截尾考虑AR模型p取PACF显著截尾处的滞后阶数ACF截尾、PACF拖尾考虑MA模型q取ACF显著截尾处的滞后阶数两者都拖尾ARMA模型阶数需要另想办法但说实话实际画出来的图很少这么干净。尤其带季节性的序列ACF会在12、24、36这些位置出现明显尖峰这是季节项的信号。所以这份零售数据只做普通ARIMA不行必须上SARIMA也就是带(P,D,Q)_12的季节ARIMA。3.2 用信息准则做网格搜索看图只能缩小范围真正定阶我更喜欢用网格搜索配合AIC。AIC即赤池信息准则它在拟合优度和模型复杂度之间取平衡数值越小代表模型越“划算”。MATLAB里可以循环训练多个候选模型挨个比较% 候选阶数范围 pList 0:3; dList 0:1; qList 0:3; PList 0:2; DList 0:1; QList 0:2; S 12; bestAIC inf; bestModel []; results []; for p pList for d dList for q qList for P PList for D DList for Q QList Mdl arima(p,d,q); Mdl.Seasonality S; Mdl.ARLags 1:p; % 如果p0会自动忽略 Mdl.MALags 1:q; Mdl.SARLags S*(1:P); % 季节自回归滞后 Mdl.SMALags S*(1:Q); % 季节移动平均滞后 try [EstMdl, ~, logL] estimate(Mdl, sales, Display, off); [~, bic] aicbic(logL, numParams(Mdl), length(sales)); if bic bestAIC bestAIC bic; bestModel EstMdl; end catch continue; end end end end end end end注意这个循环可能跑比较久因为组合数量不少。如果嫌慢可以先缩小候选范围或者把差分阶数固定成你已经验证过的d1, D1只去搜索p、q、P、Q。我一般先粗搜一轮确定大致区域后再在最优阶数邻近的几个值之间细搜。3.3 建模时的参数代表什么有些教材喜欢直接写模型公式我换个方式解释p现在这个月的销量受之前几个月销量影响的程度。12月卖得好1月是不是也会连带着好一点p管的就是这种“自己影响自己”的关系q现在这个月的“意外波动”。比如某月搞促销突然冲高这个冲击会不会延续到下个月q管的就是这种随机冲击的残留D和Q作用同上只不过是针对“今年12月影响去年同期12月”这种跨年关系理解了这些你就明白为什么零售数据一定要有季节项了。因为年末大促、周期备货这些效应每年都在你不给模型季节通道它就只能靠非季节项硬学效果会差很多。4. 完整代码从数据到预测的一段式流程4.1 直接可以跑的完整脚本这里给出一份可以直接复制运行的完整代码。这个版本我会把数据处理、模型训练、预测和画图全串起来%% 1. 加载数据 load Data_RetailSales; sales Data_RetailSales.RetailSales; % 具体字段名按工作区实际调整 dates Data_RetailSales.Date; %% 2. 快速可视化 figure; plot(dates, sales, LineWidth, 1.2); title(零售销售原始序列); grid on; %% 3. 平稳性检验 [h, pValue] adftest(sales); fprintf(ADF检验p值: %.4f\n, pValue); %% 4. 模型定义 % 本例采用经过网格搜索确认的阶数 p 1; d 1; q 1; P 1; D 1; Q 1; S 12; Mdl arima(p,d,q); Mdl.Seasonality S; Mdl.ARLags 1:p; Mdl.MALags 1:q; Mdl.SARLags S*(1:P); Mdl.SMALags S*(1:Q); %% 5. 模型估计 [EstMdl, EstParamCov, logL] estimate(Mdl, sales, Display, params); %% 6. 残差诊断 res infer(EstMdl, sales); figure; subplot(2,1,1); autocorr(res); title(残差ACF); subplot(2,1,2); parcorr(res); title(残差PACF); %% 7. 未来12个月预测 [forecastY, forecastMSE] forecast(EstMdl, 12, sales); forecastCI forecastY 1.96 * sqrt(forecastMSE) * [-1 1]; %% 8. 画预测结果 figure; h1 plot(dates, sales, LineWidth, 1.2); hold on; futureDates dates(end) calmonths(1:12); h2 plot(futureDates, forecastY, r-, LineWidth, 1.5); h3 plot(futureDates, forecastCI(:,1), r--, LineWidth, 0.8); plot(futureDates, forecastCI(:,2), r--, LineWidth, 0.8); legend([h1 h2 h3], {历史数据, 预测值, 95%置信区间}, Location, northwest); title(零售销售未来12个月预测); xlabel(时间); ylabel(销售额); grid on;4.2 脚本里几个关键步骤的意图infer函数用来提取模型残差。这一点很多人容易跳过去直接拿预测结果说事。实际上残差诊断是判断模型是否把信息提取干净的关键。如果残差序列里还能看出明显的自相关说明模型阶数不够信息还留在里面没被解释干净。这时盲目预测结果看着再漂亮也是碰运气。forecast的第二个输入 12 表示预测未来12个点也就是未来12个月。第三个输入是历史观测值模型会拿它作为起点往后递推。注意forecast不是重新训练模型它用的是你已经估计好的EstMdl只是把过去的路径延伸到未来。置信区间我直接用1.96 * sqrt(forecastMSE)构造。这里隐含假设残差正态分布实际数据不一定满足但作为快速评估够用了。严格的预测区间应该用模拟法构造后面我可以补一段但这对于题主这种快速实战场景不是必须。4.3 模型类型在代码里的体现很多刚接触的人搞不明白arima(p,d,q)后面的Seasonality、SARLags、SMALags是什么意思。这里有个关键点MATLAB的arima对象当你设定Seasonality 12后模型就等于自动变成 SARIMA 形式。此时ARLags指定非季节AR项的滞后阶数比如1:pSARLags指定季节AR项的滞后位置比如12*(1:P)MALags和SMALags对应非季节和季节MA项为什么SARLags要乘12因为季节效应发生在相同的月份位置12月影响12月24月影响24月。你不指定SARLags的话MATLAB默认把季节项当成12阶MA处理那模型含义就完全不同了。5. 预测效果评估模型好不好不能只靠眼睛5.1 用滚动预测模拟真实场景预测这种事光看训练集拟合得好坏没意义。真正的考验是拿历史数据做“回头测”把前80%的数据当训练集后20%当测试集用训练好的模型去预测测试集那一段再跟真实值对比。% 划分训练集和测试集 trainLen floor(length(sales) * 0.8); trainData sales(1:trainLen); testData sales(trainLen1:end); % 在训练集上估计模型 Mdl2 arima(1,1,1); Mdl2.Seasonality 12; Mdl2.ARLags 1; Mdl2.MALags 1; Mdl2.SARLags 12; Mdl2.SMALags 12; [EstMdl2, ~, ~] estimate(Mdl2, trainData, Display, off); % 预测整个测试集长度 [testForecast, testMSE] forecast(EstMdl2, length(testData), trainData); % 计算误差 rmse sqrt(mean((testData - testForecast).^2)); mae mean(abs(testData - testForecast)); fprintf(RMSE: %.3f, MAE: %.3f\n, rmse, mae);5.2 评估指标怎么解读RMSE和MAE一个惩罚大误差一个反映平均绝对误差水平。但在销量场景里我更建议同时看相对误差MAPEmape mean(abs((testData - testForecast) ./ testData)) * 100;如果MAPE在10%以内对于零售销量这种噪声不小的数据算很不错了。要是飙到20%以上就该回头查阶数、检查是否有异常月份或者看看要不要加外生变量。我自己回头看这份零售数据的滚动预测时一个比较明显的规律是预测前3个月误差可控越往后误差越大。这很正常ARIMA本质上是靠历史惯性外推时间越远不确定性越大。所以做业务预测时我会建议别一口气预测太久拆成“每季度滚动重训一次”的方式更实用。5.3 模型对比增加说服力做项目汇报时单说“我建了个ARIMA模型”说服力不够最好摆几个对比。最简单的做法是拿一个基准模型跟SARIMA比。比如用“上一年的同月值”作为朴素预测% 朴素季节基准用去年同月数据 naiveForecast sales(trainLen1-12 : trainLen-12); % 不太严谨这里示意 % 正确写法应该按月份对齐这种基准模型简单到不行但如果ARIMA连它都比不过说明模型白搭了。实际对比中ARIMA通常能赢因为它不仅用了去年同期信息还综合了临近几个月的动态变化比单纯的“去年同月”灵活得多。做这种对比还有个好处能让你更冷静看待模型效果。ARIMA不是魔法它只是把“季节性、趋势、滞后影响”这几件事用一套框架整合起来了效果优劣最终要靠数据说话。6. 调参细节与常见坑我替你踩过了6.1 关于MATLAB版本和工具箱的提醒做ARIMA必须要有Econometrics Toolbox有些旧版本或者基础版MATLAB没装的话运行arima会直接报错“未定义函数或变量”。遇到这种情况先确认工具箱是否可用再考虑换数据或换实现方式。另外不同版本的arima对象字段名有些细微差别老版本可能是ARLags需要额外的set方法设置新版本直接在构造后点号赋值就行。脚本跑不起来的时候先检查版本差异不一定是代码逻辑问题。6.2 模型不收敛先别急着加阶数estimate有时候会报“无法计算标准误差”或者迭代半天不收敛。常见原因有三个阶数太高导致参数冗余尤其p和q同时使劲调大的时候模型参数之间高度相关优化器找不到干净的极值点数据里有极端值。比如某个月销量突然暴跌暴涨会严重干扰最大似然估计优化初值不合适MATLAB有时候给的初值离最优解太远导致数值震荡我的处理顺序是先检查有没有异常月份其次简化模型从(1,1,1)(1,1,1)_12开始确认基线效果后再慢慢加复杂度最后再考虑调整估计选项里的优化算法和容差。6.3 预测值明显偏低或“糊成一条直线”这个现象挺常见尤其是对带强季节性的数据。原因多半是季节项没有正确设定或者D选得不对。如果只做普通差分没有季节差分模型会把季节性当成某种“平均噪声”预测出来自然趋平。遇到“预测直线”优先检查是不是忘了设Seasonality12以及有没有在网格搜索里包含D和季节项的组合。6.4 残差诊断不过关怎么办残差ACF图里如果12、24这些位置还有显著尖峰说明季节信息没提取干净。两个方向一是提高季节项阶数把P或Q从1调到2二是重新检查数据有时候节假日效应在不同年份发生的时间不完全对齐会导致季节模式不稳定此时可以尝试加节假日哑变量。这份零售数据相对规整调大季节阶数通常能解决问题但不要盲目加高否则容易过拟合。6.5 常见问题速查表现象可能原因处理方式报错未定义arima缺少Econometrics Toolbox检查工具箱并重新安装估计不收敛阶数过高或数据异常减阶数检查异常值调整优化选项预测结果接近直线季节项未设置或D不对设置Seasonality加入季节差分残差ACF仍有显著尖峰季节效应没提取干净调大P或Q加入哑变量MAPE过高模型定阶不合适网格搜索重新定阶尝试加入外生变量预测置信区间过宽差分过度减少差分阶数检查d是否过大7. 一个我常用的收尾技巧多步预测拆成滚动重训最后分享一个我实际项目里常用的做法。刚才提到过滚动回头测其实生产环境的预测也应该做成滚动式。不要训练一次模型就反复预测一年而是每个月结束后把新数据塞进样本重新估计一遍模型参数。ARIMA模型参数更新成本低重训一次也就几秒钟完全没必要一劳永逸。% 滚动预测示意每来一个月的新数据就重训一次 for t trainLen1 : length(sales) currentData sales(1:t-1); [~, ~] estimate(Mdl2, currentData, Display, off); [nextForecast, ~] forecast(Mdl2, 1, currentData); predStore(t - trainLen) nextForecast; end这样做的逻辑很简单模型学到的“最近规律”永远是最新的促销活动、消费习惯变化都会被及时吸收。如果你做的是连续多个月的预测这个方法比一次性预测到底稳得多误差至少能降一个档次。我个人折腾这套数据下来最大的体会是ARIMA不难难的是你得对每个步骤有感觉——为什么差分、为什么设季节项、为什么定这个阶数。有了这层理解配合网格搜索和滚动验证就算数据换成别的行业你也能很快搭出一套靠谱的预测流程。这份零售数据只是起点同样的套路换个电商、餐饮、库存场景照样能用。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →