时间序列预测这块这几年深度学习确实火LSTM、Transformer一个个往上堆仿佛不用神经网络就不叫预测。但我在实际项目里折腾了一圈下来发现很多业务场景尤其是数据量不大、要求解释性强、需要快速出结果的场景ARMA这个“老古董”反而特别能打。今天不整虚的直接上Matlab实操从数据预处理到模型定阶、参数估计、模型检验再到预测输出手把手把完整流程走一遍顺便把我在项目里踩过的坑也一并交代清楚。1. ARMA模型的分析对象与建模前提1.1 ARMA到底在做什么ARMA模型全称是AutoRegressive Moving Average自回归滑动平均模型。它由两部分组成AR部分关注的是时间序列自身的历史值对当前值的影响MA部分关注的是过去若干期的随机误差对当前值的影响。把这两部分合起来就构成了一个对平稳时间序列进行线性建模的经典框架。用数学形式表达就是当前值等于一个常数项加上前p期的观测值各自乘以对应的自回归系数再加上前q期的随机误差各自乘以对应的滑动平均系数最后再加上本期的随机误差项。Matlab里用arima(p,d,q)函数来创建模型对象时p、d、q这三个参数对应的就是AR阶数、差分阶数、MA阶数。我在项目中常用它来解决两类问题一类是销量或流量这类业务指标的短期预测另一类是设备运行参数的异常趋势捕捉。前者的典型特征是数据量少往往只有几百条日粒度记录后者的典型特征是信号带有明显的自相关性当前时刻的数值和过去几个时刻的数值之间存在较强的依赖关系。这两种场景如果直接上深度学习很容易因为样本不足导致过拟合而ARMA的参数量少、结构透明、计算开销低反而能稳定产出可用结果。1.2 使用ARMA的前提条件ARMA模型有一个硬性前提序列必须是平稳的。所谓平稳通俗地讲就是序列的统计性质不随时间推移而变化均值始终围绕着一个固定水平波动方差不随季节或趋势变化出现明显起伏。我遇到过不少初学者把非平稳数据直接丢进arima函数里拟合结果模型输出的预测值要么是一条直线要么不断发散完全无法使用。原因在于非平稳序列中的趋势成分和季节成分会让自相关系数产生虚假的相关性导致模型把趋势当作周期性的规律来学习自然预测不准。处理非平稳序列的经典手段是差分。一次差分可以去除线性趋势二次差分可以处理曲率变化更复杂的趋势。如果数据带明显的季节性还需要先做季节差分或者改用SARIMA模型的变体。在Matlab里做差分非常方便直接diff(x)就能实现也可以把arima模型的d参数直接设为1或2让模型在拟合时自动完成差分操作。1.3 为什么在深度学习时代还要用ARMA我并不是否定深度学习的价值而是建议做技术选型时先算一笔账。LSTM这类模型擅长从大量历史数据中学习复杂的非线性模式但如果你的样本量只有几百条神经网络的参数量远远超过信息量模型很难学到稳定的映射关系结果往往是训练集上表现不错测试集上一塌糊涂。ARMA模型的优势恰恰体现在小而美的场景上。它的参数数量通常只有几个到十几个拟合过程有成熟的统计学理论支撑参数估计结果有明确的统计检验指标可以评判预测结果还自带置信区间这对业务决策而言是非常实用的。例如我在做某款消费品日销量预测时一共只有180天的数据用ARMA(3,0,2)模型做7天预测平均绝对百分比误差控制在8%以内效果完全够用。当然如果数据量充足、且存在明显的非线性和长程依赖特征LSTM或Transformer确实可能更合适。但在动手建模之前先用ARMA跑一遍基线能够帮助你快速判断数据的线性依赖强度也为后续复杂模型的对比提供一个基准线。很多时候ARMA跑出来的结果已经能满足业务需求压根不需要上深度模型。2. 数据预处理与平稳性检验的Matlab实操2.1 数据清洗与格式规范化拿到原始数据之后第一件事不是建模而是把数据清洗干净。Matlab里处理时间序列数据我习惯把数据存成两列第一列是时间戳第二列是对应的观测值。时间戳建议用datetime类型存储读取Excel或CSV数据时用readtable或readmatrix直接导入再用datetime函数转换格式最后用timeseries或直接使用数值数组作为后续模型的输入。缺失值处理是另一个高频问题。工业数据里经常出现某一天没有记录的情况如果不处理直接建模拟合函数会报错而且预测结果也会因为时间轴不连续而产生偏差。常用的处理策略有三种线性插值适合变化平缓的序列前向填充适用于记录粒度较粗的场景移动平均平滑则能兼顾局部趋势。我在实际项目中会优先选用线性插值因为它的偏差可控且实现简单Matlab里用fillmissing(x, linear)一行代码就能搞定。异常值也是必须处理的。我通常先用isoutlier函数基于中位数绝对偏差进行检测再结合业务经验判断这些异常点是否真实反映了特殊情况。比如大促当天销量暴增这不叫异常值这是业务规律应该保留但某天记录被错误地多写了一个零这就是必须修正的数据错误。建模用的数据一定要干净否则模型学习到的规律会被这些噪声点带偏。2.2 用adftest做单位根检验平稳性检验在Matlab里最常用的是ADF检验全称Augmented Dickey-Fuller检验。它的核心思想是检验序列是否存在单位根如果存在单位根则序列非平稳如果拒绝了“存在单位根”的原假设则序列平稳。代码实现很直接x data(:, 2); [h, pValue] adftest(x); disp([ADF检验p值: , num2str(pValue)]);输出结果中h等于1表示拒绝原假设序列平稳h等于0表示无法拒绝原假设序列存在单位根需要差分处理。注意adftest函数默认包含常数项的检验回归形式如果你的序列有明显的趋势漂移需要调整模型形式把model参数设为AR或TS。我碰到过一种容易误判的情况一个带有缓慢上升趋势的序列ADF检验有时会给出“拒绝单位根”的结果因为序列在局部范围内看起来围绕一条缓慢上升的线波动。但严格来说有趋势的序列均值不恒定不满足平稳性定义。为了稳妥可以同时观察自相关图和偏自相关图或者做KPSS检验作为交叉验证。2.3 对非平稳序列执行差分转换一旦确定序列非平稳差分操作就派上用场了。一次差分dx diff(x)能够去除线性趋势等价于在arima模型中设置d1。差分后的序列通常会变得平稳这时候再运行一次adftest确认结果。如果一次差分后检验仍显示非平稳就需要二次差分ddx diff(dx)。需要提醒的是不要盲目追求高阶差分。差分阶数过高虽然能让序列通过平稳性检验但会过度去除信息导致预测结果失去原有的量级特征。我的经验是一阶差分解决90%以上的趋势问题二阶差分只用于曲率变化比较明显的非线性趋势场景。差分后的数据用于模型拟合和预测得到的预测结果是差分值最终要还原成原始量纲的预测值。还原的操作是累加原始序列的预测值等于最后一个原始观测值加上差分预测值的累积和。在Matlab里如果使用arima(p, d, q)且d设为1forecast函数会自动完成差分还原输出结果直接就是原始量纲的预测值这一点相当省心。3. ARMA模型的定阶、估计与诊断检验3.1 通过相关图初步判断阶数要把ARMA模型用到具体的p和q阶数定下来通常从自相关函数ACF和偏自相关函数PACF入手。ACF衡量序列与其滞后k期序列之间的相关性PACF则是在剔除了中间滞后项的影响之后序列与其滞后k期序列之间的偏相关性。在Matlab里画相关图非常方便autocorr(x); parcorr(x);判读规则是如果ACF在滞后q阶之后截尾PACF呈现拖尾则适合MA(q)模型如果PACF在滞后p阶之后截尾ACF呈现拖尾则适合AR(p)模型如果ACF和PACF都呈现拖尾则适合ARMA(p,q)模型。所谓截尾就是相关系数在某个滞后阶数之后突然跌入置信区间内且不再显著拖尾则是相关系数逐渐衰减但始终存在一定程度的显著值。这套规则在实际数据上往往不会那么清晰尤其是小样本情况下相关系数本身的波动就比较大。因此相关图只能作为初步判断的依据最终阶数要用信息准则来比较筛选。3.2 用aicbic进行信息准则定阶信息准则是在模型拟合优度和参数复杂度之间做权衡的指标。AIC和BIC都遵循“越低越好”的原则其中BIC对参数数量的惩罚更重因此在样本量较大时倾向于选择更简洁的模型。我在Matlab中的做法是写一个双循环遍历p从0到5、q从0到5的所有组合对每一组(p,q)拟合ARMA模型再计算AIC和BIC值最后选出一个综合最优的模型。bestAIC inf; bestPQ [0, 0]; for p 0:5 for q 0:5 if p 0 q 0 continue; end mdl arima(p, 0, q); try fit estimate(mdl, x, Display, off); [aic, bic] aicbic(fit.LogLikelihood, numParams(fit), length(x)); if aic bestAIC bestAIC aic; bestPQ [p, q]; end catch continue; end end end disp([最优阶数: AR( num2str(bestPQ(1)) ) MA( num2str(bestPQ(2)) )]);有几个细节值得注意。一是拟合函数estimate在遇到某些阶数组合时可能不收敛需要用try-catch把异常吞掉否则循环直接中断。二是不能机械地选择AIC最低的模型还要看参数估计的显著性。如果某个自回归系数的t统计量过小说明这项参数不显著可以考虑降低阶数重新拟合。三是样本长度不同AIC和BIC的最优结果可能不一致我的取舍原则是短期预测参考AIC长期预测参考BIC因为BIC惩罚更大选出的模型更简洁泛化能力通常更好。3.3 用最大似然估计拟合模型参数定好阶数后用estimate函数进行参数估计。estimate默认使用最大似然估计MLE来求解参数这是一个迭代优化过程从初始参数出发不断调整参数值使得在当前数据下观察到该序列的概率最大化。mdl arima(bestPQ(1), 0, bestPQ(2)); fit estimate(mdl, x, Display, params);运行后会输出一张参数表包括常数项、AR系数、MA系数、方差等参数的估计值、标准误差、t统计量和p值。t统计量的绝对值大于1.96说明参数在5%显著性水平下显著。要重点关注有没有不显著的参数如果有通常的做法是适当调整阶数后重新拟合。我还想多说一句关于AR系数符号的坑。Matlab的arima模型输出AR系数时模型方程是带负号的约定当前值等于常数项减去各滞后项的AR系数乘以往期值再加上MA部分和误差项。因此输出结果里的AR系数如果显示为负值实际上对应的是自回归方程里的正相关关系。我见过不少人在手工核对模型方程时被这个符号约定绕晕实际上你只需要用forecast函数直接预测即可不必手工代入方程计算。3.4 残差白噪声检验与模型有效性判断参数估计完成后必须验证模型是否充分提取了数据中的信息。方法是检验残差是否为白噪声如果残差序列不再存在显著的自相关性说明模型已经把数据中的线性依赖信息都抓住了。Matlab中实现残差检验的代码如下res fit.ResidualsRaw; [h, pValue] lbqtest(res, Lags, [5, 10, 15]); disp([Ljung-Box检验: h, num2str(h), , p, num2str(pValue)]);lbqtest是Ljung-Box检验函数原假设是残差序列不存在自相关。h0且p值大于0.05说明残差通过白噪声检验模型是有效的。如果检验未通过说明残差中还残留着相关信息可能需要增加AR或MA的阶数或者考虑季节成分。我还会额外做一次残差的正态性检验用的函数是jbtest。虽然正态性不是ARMA模型的严格前提但如果残差严重偏离正态分布参数的置信区间估计就可能不太可靠预测结果的置信区间也可能过于乐观。残差可视化这一步也不可省略画个残差自相关图和三阶标准差的95%置信带比单纯的数值检验更能直观暴露结构性问题。如果残差在某个滞后阶数处明显超过置信带说明模型中遗漏了该阶数的动态依赖关系。4. 项目实操案例分析某零售品日销量预测4.1 数据背景与建模目标我手上有一个零售品日销量的真实项目数据一共240条日粒度记录前180天用于模型训练后60天用于评估预测效果。数据呈现出两个特点整体有轻微上升趋势日与日之间存在明显的相关性大促日销量会出现尖峰但大促后通常会有一到两天的低谷。这样的数据结构非常适合用ARMA类模型做短期预测。建模目标明确为预测未来7天的日销量评估指标用平均绝对百分比误差MAPE和均方根误差RMSE。之所以不用单一的RMSE是因为销量数据存在明显的量级波动RMSE偏重于大误差样本MAPE能更好地反映相对误差水平。4.2 基于训练集的完整建模流程我用前180天数据完成了完整的建模流程。第一步做原始数据的平稳性检验ADF检验结果显示p值为0.2以上无法拒绝单位根原假设序列非平稳。第二步做一阶差分再次运行adftestp值小于0.01序列平稳性通过。第三步进行模型定阶。我先观察差分后序列的ACF和PACF图ACF在滞后1到3阶处有一定显著性随后衰减PACF在滞后1阶处截尾之后快速衰减。初步判断倾向于AR(1)MA(2)或AR(3)MA(0)的结构。随后运行双循环的aicbic定阶程序综合AIC和BIC结果选出ARMA(3,2)作为最优模型。第四步执行参数估计拟合结果中AR(2)系数的t统计量略低于显著性阈值我尝试把模型降为ARMA(2,2)AIC只增加了不到2但所有参数都通过了显著性检验最终选用更简洁的ARMA(2,2)。第五步对残差执行Ljung-Box检验滞后阶数取5、10、15时全部通过残差不拒绝白噪声假设模型有效。4.3 预测未来7天销量并计算误差用训练好的模型对后60天数据的前7天做预测Matlab代码为[forecast, forecastCI] forecast(fit, 7, Y0, x_train);forecast函数需要传入两个关键信息预测步数和用于预测的历史数据。预测步数设为7历史数据使用训练集最后一段观测值函数输出预测均值和置信区间。这里有一个细节要注意forecast内部会使用fit模型对象里保存的估计参数来生成预测不需要再手动传入参数但训练集数据的末尾部分会直接影响预测的初始路径因此要确保Y0使用的是原始序列最后7个真实观测值。实际预测结果与真实值对比后计算得到MAPE为7.6%RMSE约为日均销量的11%。从业务角度看这个误差水平完全可以接受。我还对比了直接用AR(1)模型的预测结果MAPE反而会上升到11.5%差距明显说明MA部分的加入确实有效捕捉了短期波动规律。4.4 预测结果的置信区间解读forecast函数输出的置信区间默认是95%水平。实际项目中我通常把置信区间一并输出给业务方用于辅助判断预测的可靠性。比如某天预测销量为220件置信区间是[195, 245]业务方可以据此设置库存的安全边界按置信区间上限备货从而降低断货风险。置信区间的宽度会随着预测步数的增加而逐渐扩大这是因为预测误差随着步长累积越来越大。这一点能够直观说明一个事实用ARMA模型做长周期预测的意义不大预测步数一般不要超过训练数据长度的十分之一。如果业务需要预测30天以上我会建议改成预测滚动更新的方式每隔几天用最新数据重新估计模型参数和预测值用滚动窗口来对冲单次预测的误差累积。5. 常见问题与排查技巧实录5.1 estimate函数不收敛estimate函数在拟合ARMA模型时有时会报出“无法收敛”或“参数估计不稳定的警告”。我在实际项目中遇到过多次排查思路有固定套路。首先是检查数据是否包含过大或过小的数值。如果序列的数值量级在百万级别似然函数的梯度计算容易出现数值问题需要先对数据做标准化处理比如除以序列的标准差等预测结果出来后再乘以标准差还原。其次是检查定阶是否过于激进阶数过高会导致参数空间出现近似的非唯一解优化器在多个相近的极值点之间反复震荡。我的建议是从低阶开始逐级增加阶数不要一上来就尝试ARMA(8,8)。如果依然不收敛可以考虑切换优化算法。estimate内部支持通过Options参数传入优化选项我习惯把optimoptions中的MaxIterations调高或者把TolFun适当放宽给优化器更大的搜索空间。5.2 预测结果持续走平或发散预测结果走平有两种常见情况。第一种是数据经过差分后建模预测的差分值很小且趋于零还原为原始量纲后就表现为一条水平线。这通常说明模型没有捕捉到足够强的动态依赖关系要么阶数定得太低要么原本序列的数据生成过程更接近随机游走。第二种情况是差分阶数过高过度差分把合法信息也一并去掉了最终预测自然变得平坦。预测结果发散则通常意味着模型参数估计出了问题常见原因包括MA部分存在单位根、参数估计不显著但仍保留在模型中、或者数据中存在未被识别的异常值。处理发散问题时我会先检查参数表里MA系数的绝对值是否接近1如果接近1则降低q阶接着检查残差检验是否通过若未通过则需要调整模型结构。5.3 多步预测的误差累积问题多步预测的误差累积是ARMA模型绕不开的宿命。单步预测误差3%不代表7步预测误差只有3%乘以根号7实际情况会更差因为每一步预测的误差都会作为下一步预测的输入误差之间还存在正相关。缓解误差累积的方法有三种。第一种是滚动预测法每预测出新的一天就把真实值纳入历史数据重新估计模型参数。第二种是调节预测起点用最新的数据来预测减少历史信息的衰减影响。第三种是在模型中加入外生变量或干预变量比如特殊的节假日事件、大促活动等这些信息无法被纯时间序列模型自动捕捉。5.4 画图工具不显示结果最后说一个小坑。在部分Matlab版本中autocorr和parcorr函数绘制的图像可能被某些图形设置选项隐藏导致画图窗口空白。遇到这种情况先运行figure命令新建绘图窗口再检查hold on或hold off状态是否影响后续图层叠加必要时用clf清空当前图形对象。还有一个更隐蔽的情况是数据中包含NaN值autocorr函数默认会忽略NaN但如果NaN占比过高相关系数估计的可靠性会下降所以数据清洗时务必先处理好缺失值。6. 实用经验总结与工具选型建议6.1 我个人在实际项目中的几个习惯经过多次时间序列预测项目的实践我沉淀出一套固定的操作习惯代码格式和执行流程保持稳定能够显著减少低级错误。第一是永远先画图再建模。把原始序列图、差分序列图、ACF图、PACF图一次性画完肉眼观察到的东西比任何统计检验都直观这是最有效的安全检查。第二是建模前先跑一个简单的AR(1)基线确认数据确实存在一阶自相关再往复杂的模型方向走。第三是训练集和测试集严格分离调参和定阶只能依赖训练集数据避免数据泄漏导致的虚假高精度。第四是保存每一步的中间结果。从数据清洗后的序列、差分后的序列、每个候选模型的AIC/BIC表、最终模型参数表到预测结果全部以变量名和版本号的形式保存在工作区中必要时导出为.mat文件或Excel存档。一旦后续发现异常可以逐步回溯定位问题出现在哪一环而不是从头再跑一遍。6.2 ARMA与LSTM的适用场景边界在实际项目选型时我的判断标准很简单数据量在500条以下业务需要解释预测依据或者时间紧迫来不及调参时优先使用ARMA数据量在几千条以上存在明显的长期依赖和非线性模式并且有GPU算力支撑时再考虑LSTM等深度模型。这并不是说LSTM在数据量小时完全不能用而是说其效果不稳定调参成本高。我在一个时序异常检测项目中也用过Matlab的LSTM工具箱数据量1000条左右LSTM确实在某些序列上表现优于ARMA但训练时间和对超参数的敏感度让人很头疼。而ARMA模型在同样的数据上从定阶到出预测结果不到两分钟还能输出置信区间对于多数业务决策场景来说这种效率是决定性的。6.3 后续可以扩展的方向ARMA模型本身有多个自然的扩展方向。如果数据存在明显的季节性周期可以在ARMA的基础上增加季节项变成SARIMA模型。Matlab的arima类其实可以支持指定季节滞后参数在创建模型对象时把Seasonality属性设为周期长度即可拟合过程和ARMA几乎一样但能够有效捕捉周期性规律。如果预测目标同时受到外部因素影响可以在模型中增加外生变量变成ARIMAX模型。estimate函数接收输入数据时可以指定X矩阵作为外生回归变量把促销活动、天气温度、节假日等业务信息纳入模型。这个扩展在业务场景中非常实用而且实现成本极低。如果数据中存在明显的方差波动聚集现象比如金融序列的波动率时高时低可以考虑GARCH族模型。Matlab的garch类专门用于这类分析它能够对波动率本身建模与ARMA模型对均值的建模互为补充。实际项目中可以先用ARMA拟合均值部分再对残差应用GARCH形成完整的均值方差联合建模框架。我在实际使用中最深的体会是模型没有新老之分只有合适与不合适之分。ARMA这个老工具在它擅长的领域里依然好用得很关键是要把每一个步骤都理解到位从平稳性检验到定阶再到残差诊断每一步都有它存在的意义。跳过任何一步预测结果的质量都会打折扣。希望这篇实操分享能帮你少走一些弯路也欢迎多交流各自在时间序列预测项目中遇到的案例和心得。
阅读完成 · 觉得有帮助?