尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python ARIMA时间序列预测实战:完整流程与案例

Python ARIMA时间序列预测实战:完整流程与案例 如果你正对着几十行销售数据发愁老板让你预测下个月的洗发水销量而你脑子里只有均值、折线图这些最朴素的工具——这篇文章就是给你准备的。时间序列预测在业务里实在太常见了月度销量、日活用户、库存需求、设备指标拿到手都是一列按时间排序的数字。而Python里最经典、最稳定、也最容易上手的建模方案就是ARIMA。今天我用一个非常经典的洗发水销售数据集把从数据准备、平稳性检验、模型定阶、拟合诊断到预测评估的完整流程从头到尾捋一遍所有代码都会贴出来你照着敲一遍基本就能迁移到自己的数据上。ARIMAAutoregressive Integrated Moving Average这三个字母拆开来看AR是自回归说明当前值受过去值影响I是差分用一次或多次求差把非平稳序列掰成平稳序列MA是移动平均把历史误差也纳入考虑。一列时间序列数据只要它内部存在“过去影响现在”的线性规律ARIMA就能把它挖出来然后外推几步预测。这篇博文适合谁刚接触Python数据分析的学生、做销售或运营预测的从业者、以及那些手里攒了一批历史数据但不知道怎么建模的人。我会用一个月度洗发水销售数据作为完整案例带着你走一遍全流程。1. 什么时候该用ARIMA什么时候别硬上1.1 模型边界ARIMA能做什么、不能做什么很多人第一次接触到时间序列就听说ARIMA很厉害于是拿到什么数据都想往上套。实际上ARIMA的适用边界非常清晰它面向的是单变量、线性关系、中短期预测的场景数据量通常在30到几百个时间点之间。你手里只有一个销量字段没有促销、天气、竞品价格这些外部特征那么ARIMA就是性价比极高的一种选择。ARIMA不擅长的事情我提前说清楚免得你踩坑。第一它不适合强季节性数据。如果销量每年6月、12月都有明显波峰而且这个周期规律一年一次那你需要的是SARIMA带季节分量的ARIMA或者Prophet这类能显式建模季节性的工具。第二它不适合受外部事件剧烈冲击的序列。比如突然搞一场大促销量翻了三倍这种由外因引起的突变ARIMA基本反应不过来因为它只看历史自身的规律不看外部原因。第三它不适合超长期预测。ARIMA本质是“用过去的惯性推未来”预测步数拉得越长误差积累越大预测曲线往往会收敛到历史均值附近这属于模型本身的数学特性不是代码写错了。还有一个容易忽视的前提数据必须在时间索引上有固定频率。月度数据就是一个月一个点日均数据就是一天一个点中间不能有大量缺失或者乱序。如果你的数据是“某个月有、下个月没有”的稀疏记录先把缺失值补上或重采样成固定频率再做ARIMA。1.2 洗发水销售预测的业务场景为什么要选洗发水销售这个例子因为它是单变量月度数据里非常典型的代表。洗发水作为日化快消品用户群体稳定、复购周期短、受季节影响相对温和销量在短期内主要受自身历史水平、渠道铺货节奏和品牌稳定性的影响。换句话说它内部具有较强的“惯性”这个月卖得好下个月一般也不会差到哪里去这个月跌了下个月可能还会延续跌势。这种惯性正是ARIMA自我回归部分需要捕捉的信号。这个案例的数据一共36个月数量不算多但足够完成一次完整的建模演示。在真实业务中36个月恰好是很多快消品团队做年度计划时的最少数据要求低于这个量级ARIMA的参数波动会非常大。当然如果你手里只有12个点甚至更少我个人会建议直接放弃ARIMA改用朴素方法比如上个月的值或过去三个月的均值反而更稳。模型再花哨样本量撑不住也是白搭。2. 数据准备从原始表格到可建模的时间序列2.1 数据格式与导入这个洗发水销售数据集是Box-Jenkins时代留下的经典案例很多教材和网上教程都拿它做时间序列入门。csv文件结构很简单总共36行每行一个月的销量记录。注意一点原始数据集很可能没有真正的日历日期只有“第1个月、第2个月”这样的序号。遇到这种情况我们不能直接拿去建模必须自己补一个连续的时间索引。import pandas as pd import numpy as np import matplotlib.pyplot as plt df pd.read_csv(shampoo.csv) print(df.head()) print(df.shape)如果打印出来发现只有一列销量甚至列名都不对不用慌自己构造一个日期索引然后覆盖进去就行df[月份] pd.date_range(start2022-01-01, periodslen(df), freqMS) df df.set_index(月份) df.columns [销量] print(df.head())这里的关键是freqMS。MS表示每月开始日Month Start这是月度数据最常用的频率标识。不要用M因为M在Pandas里已经被改成了月份末尾Month End容易跟你预想的时间点差一个月。构造日期索引的时候起始日期选哪个不重要重要的是频率必须连续且唯一。2.2 索引与频率新手最容易翻车的地方我见过太多人在这一步出错所以单独拿出来强调。ARIMA模型在statsmodels里是按行顺序建模的也就是说它默认你的数据已经按时间从早到晚排好了。如果你读取原始表格后没做任何处理而原始文件里的行顺序恰好是乱的那么模型训练出来的结果就会一团糟。处理办法很简单df df.sort_index()另外要注意数据类型的坑。如果销量这一列读进来是字符串比如原始表里有逗号分隔符模型会直接报错。稳妥的做法是建模前把类型强制转换一下df[销量] df[销量].astype(float)我习惯上的做法是在建模前统一检查三件事索引是否是DatetimeIndex、索引是否单调递增、数据类型是否为浮点型或整型。任何一项不满足先修好再往下走不然后面所有诊断结果都不可信。2.3 先画图趋势、季节性和噪声看个大概数据分析里最重要的习惯是先可视化再建模。时间序列尤其如此一张图能告诉你很多信息序列有没有明显趋势是上升还是下降有没有周期性波动波动幅度是不是随着趋势在变大这些都是后续选择参数的重要参考。plt.figure(figsize(10, 5)) plt.plot(df.index, df[销量], markero, linewidth1.5) plt.title(洗发水月度销量走势) plt.ylabel(销量) plt.grid(True) plt.show()拿这个洗发水数据来说画完图后你会看到一个缓慢攀升的整体趋势从早期的每月100出头逐渐涨到后来的300左右。注意波动幅度早期大概在±20上下后期能到±40这说明方差并不完全恒定。很多教程在讲课的时候会直接把这组数据拿来演示ARIMA但实际上需要先做一次差分来把趋势去掉关于这点我下一节详细展开。3. 平稳性检验为什么“稳”这么重要3.1 什么叫平稳为什么要平稳平稳性这个概念你听过的版本估计很多什么“均值不变”“方差恒定”“协方差只与间隔有关”背起来很绕。我换个说法一个平稳的时间序列特征不会跑偏接下来一段时间的统计规律和过去一段时间的统计规律是一致的。举个例子这就像你给同事描述一个脾气稳定的人你基本能按他过去的习惯预判他今天的反应但如果这人完全捉摸不定上午还在笑下午就发火预测就没法做了。ARIMA的数学推导依赖平稳性如果序列不平稳模型的参数估计就不稳定预测结果也就失去意义。洗发水销量数据有明显的向上趋势均值在随时间移动所以大概率不是平稳序列。这时候就需要通过差分处理把“趋势”这个非平稳因素去掉。差分的思想很简单就是计算相邻两个时间点的差值df[销量_diff] df[销量].diff() df df.dropna()做完一次差分后序列变成“本月相比上个月的增量”。原来上升趋势带来的均值漂移经过差分之后在很大程度上会被消除掉后续建模可以基于这个增量去做预测最后再把增量累加回真实销量。3.2 ADF检验用数字判断是否平稳光靠肉眼看图不够严谨最好在差分前后都跑一遍单位根检验最常用的是ADF检验Augmented Dickey-Fuller Test。statsmodels里直接有现成函数from statsmodels.tsa.stattools import adfuller result adfuller(df[销量]) print(ADF统计量:, result[0]) print(p值:, result[1]) print(临界值:, result[4])判断标准很简单p值小于0.05拒绝原假设认为序列是平稳的p值大于0.05不能拒绝原假设序列存在单位根也就是不平稳。对于原始洗发水销量序列p值通常会比较高而对差分后的序列p值一般会降到0.05以下。这个“先检验、不行就差分、再检验”的循环是确定差分阶数d的标准套路。3.3 确定差分阶数d一次不够再来一次在ARIMA(p,d,q)里d就是差分的阶数。大多数实际问题只需要0或1少数情况需要2超过2的情况极其罕见。你对原始序列做一次差分后再画图、再跑ADF检验如果已经平稳那d1就够了。这里有一个很微妙的经验差分不是越多越好。每一次差分都会让序列损失信息也会放大噪声。如果序列本身已经平稳了你还要再差一次得到的新序列方差会被放大模型的预测区间也会变宽。我自己经历过不少次“为了追求平稳而过度差分”的情况最后模型的AIC不降反升预测结果也变得毛躁。所以判断标准很简单能平稳就别多差一次差分通常够用。3.4 关于“差分后怎么还原”的提醒这也是个常见的坑。很多人建模用的差分序列做出来的预测也是差分值但业务上要的是真实销量。你需要把差分的预测结果“加回去”每一步预测的累计加上最后一条真实观测值才是还原后的销量。这个操作在statsmodels里其实不需要你手动做后面讲预测的时候会提到但如果你是自己手动拼接代码千万别忘了这一步。4. 模型定阶p和q到底怎么选4.1 认识ACF和PACF两个自带规律的相关图ARIMA里剩下的两个参数p是自回归的阶数q是移动平均的阶数。定阶最经典的方法是看差分后序列的自相关函数ACF和偏自相关函数PACF图。ACF衡量的是相隔k期的两个值之间的相关性。比如系数为0.6就说明这期数值和上期数值相关程度较高。PACF则是在剔除中间所有其他滞后项影响后第k期前值对当前值的直接贡献。用一句话区分ACF看总相关PACF看净相关。from statsmodels.graphics.tsaplots import plot_acf, plot_pacf fig, axes plt.subplots(1, 2, figsize(12, 4)) plot_acf(df[销量_diff], axaxes[0], lags15) plot_pacf(df[销量_diff], axaxes[1], lags15, methodywm) plt.show()看图判断就记住一个经验法则情形ACF表现PACF表现适合模型AR(p)拖尾缓慢衰减在p阶后截尾突然变0AR(p)MA(q)在q阶后截尾拖尾缓慢衰减MA(q)ARMA(p,q)拖尾拖尾ARMA(p,q)4.2 洗发水数据差分后看图定阶实际操作里看图定阶往往没有教科书那么完美好多系数的显著性都是模棱两可的这时候就要靠后面的信息准则辅助判断。拿这组洗发水数据来说差分之后ACF大概率在lag 1或lag 2附近有一个明显的尖峰然后迅速衰减到置信区间以内这种形态更像MA(1)或MA(2)。PACF也可能在某一个滞后阶后突然收进蓝色置信区间说明AR的阶数较小。不过我的态度一直很明确ACF/PACF定阶只作为初选真正靠谱的做法是把候选的p和q组合全部试一遍用AIC等指标选最优。两者配合使用效率最高。4.3 网格搜索AIC用代码代替肉眼AIC赤池信息准则是用来权衡模型拟合优度和复杂度的指标。拟合越好AIC越小但是参数越多AIC也会惩罚性地增加。所以AIC实际上在平衡“模型解释能力”和“模型复杂度”我们需要找到那个“在不过度复杂的前提下拟合得不错”的点。写一个简单的循环遍历所有候选(p, q)组合选出AIC最小的一组from statsmodels.tsa.arima.model import ARIMA import warnings warnings.filterwarnings(ignore) best_aic float(inf) best_order None for p in range(0, 5): for q in range(0, 5): try: model ARIMA(df[销量], order(p, 1, q)) fit model.fit() if fit.aic best_aic: best_aic fit.aic best_order (p, 1, q) except Exception as e: # 有些参数组合可能无法收敛直接跳过 continue print(最优阶数:, best_order, AIC:, best_aic)注意这里我把d固定为1因为前面差分检验已经确认了d1。跑完你会发现最优的p和q都不大通常落在0到2之间。ARIMA就是这么个特点大部分实际业务场景里p和q很少会超过3如果搜索出来的最高阶数到了7、8甚至更高我建议你停下来检查一下数据是否被处理干净了而不是真去用那么复杂的模型。4.4 用auto_arima做交叉验证如果你不想手写网格搜索可以用pmdarima库里的auto_arima函数它会在后台自动做差分检验、参数搜索和模型选择一次性给出推荐结果。pip install pmdarimafrom pmdarima import auto_arima model auto_arima(df[销量], start_p0, max_p4, start_q0, max_q4, dNone, seasonalFalse, traceTrue) print(model.order)这个库很适合拿来快速做一个初判然后再用statsmodels去精细建模。但要注意auto_arima跑出来的结果不一定每次都是一样的因为它内部有随机搜索的成分在而且它对数据频率的理解不一定有statsmodels那么贴近底层所以最后建模我还是建议回到statsmodels。5. 模型拟合与诊断别急着预测5.1 用statsmodels拟合ARIMA并解读摘要确定了(p,d,q)之后直接拟合模型from statsmodels.tsa.arima.model import ARIMA model ARIMA(df[销量], order(best_order[0], 1, best_order[2])) fit model.fit() print(fit.summary())这里有一个版本细节要提醒新版statsmodels推荐用from statsmodels.tsa.arima.model import ARIMA而老教程里常见的from statsmodels.tsa.arima_model import ARIMA在0.13版本之后已经被移除。另外还有个经验是如果拟合时报“Non-stationary starting autoregressive parameters”的警告一般是因为初值选得不好可以尝试对数据先做对数变换再多做一次差分或者给fit传methodinnovations_mle来换一种拟合方式。fit.summary()的输出里有两块需要重点看。一是系数显著性看P|z|一列大部分系数对应的p值应该小于0.05如果某个项不显著可以考虑把对应的阶数去掉。二是整体信息量看AIC和BIC这两个数值用于和其他模型比较越小越好。5.2 残差检验模型已经把信号榨干了吗拟合完之后千万不要直接跳到预测先要检查残差。残差就是真实值和模型拟合值的差。一个合格的ARIMA模型残差应该像白噪声一样没有自相关、没有周期性、均值为0、方差恒定。如果残差里还有明显规律说明模型还没把数据里的信息提取干净预测自然会偏。检验方法有两类。第一类用Ljung-Box检验检验残差序列是否存在自相关from statsmodels.stats.diagnostic import acorr_ljungbox resid fit.resid result acorr_ljungbox(resid, lags[6, 12], return_dfTrue) print(result)p值如果大于0.05说明残差没有显著的自相关通过检验。第二类画图观察残差fig, axes plt.subplots(2, 2, figsize(12, 8)) axes[0,0].plot(resid) axes[0,0].set_title(残差序列) axes[0,1].plot(resid, o) axes[0,1].set_title(残差散点图) from statsmodels.graphics.tsaplots import plot_acf plot_acf(resid, axaxes[1,0], lags15) axes[1,1].hist(resid, bins15) axes[1,1].set_title(残差直方图) plt.tight_layout() plt.show()如果残差ACF图在某个滞后阶上突然超出置信区间且Ljung-Box检验p值也小于0.05那就说明残差还有信号残留。处理办法通常是调整p或q的阶数重新拟合再检验。5.3 模型诊断失败的常见原因我总结三个最容易导致诊断不通过的原因一是数据里存在未处理的缺失值或重复时间戳导致模型把异常点当成了正常规律二是季节性没有被处理例如月度数据里存在明显的年度周期那ARIMA就不够用必须用SARIMA三是参数阶数选得过大或过小模型要么学过头要么学不够。另外还有一个很容易被人忽略的事情模型诊断和预测评估的样本范围要一致。有些人训练时用了全部36个月诊断残差也全部合格然后回头预测这段历史区间发现拟合得很好就以为模型很靠谱。可这种“回头看”不能代表未来真正可靠的评估应该是拿前30个月训练后6个月作为测试看模型对未知数据的预测误差。下一节就来写这部分。6. 预测与评估真正回答业务问题6.1 留出测试集不要用全部数据做预测模型我们把36个月的数据切分一下前30个月做训练后6个月做测试。这是我自己常用的比例数据量不大时测试集占比20%左右比较合理如果你有几百个点可以多留一点做测试。train df.iloc[:-6].copy() test df.iloc[-6:].copy() model ARIMA(train[销量], order(best_order[0], 1, best_order[2])) fit_train model.fit()注意这里的模型是基于训练数据重新拟合的不要直接拿上一节用全量数据拟合的那个模型去做预测。理论上两个模型很接近但评估要讲规矩训练集和测试集必须严格分离。6.2 用get_forecast做多步预测statsmodels里有两种“预测”概念容易混淆。predict可以在训练集内做拟合后回代也能指定任意起点而get_forecast是专门用来做样本外预测的预测的起点默认在训练数据的最后。forecast_result fit_train.get_forecast(steps6) mean_forecast forecast_result.predicted_mean conf_int forecast_result.conf_int() print(mean_forecast) print(conf_int)steps6表示往后预测6个月。返回结果的索引会续在训练集的末尾之后对齐测试集非常方便。conf_int()返回的是95%置信区间也就是真实值有95%的概率落在上下界之间。预测区间这个概念在业务汇报里非常有用它比一个孤零零的点预测要诚实得多如果一个月的销量预测值是250区间是[200, 320]你就知道不确定性到底有多大做库存计划时能留出缓冲。再强调一次差分还原的问题如果你是用原始销量训练模型那么get_forecast返回的结果直接就是预测销量不需要自己手动还原。如果你中途先对销量做了diff()再训练那么预测值是差分值需要做累加还原。这两条路径我建议直接选第一条让ARIMA内部帮你处理差分也就是在order(p,1,q)里指定d1而不是自己手动差分后再建模。这样代码更简洁也少犯错。6.3 用MAE、RMSE、MAPE评估预测效果预测完之后拿预测值和测试集真实值做对比。这三个指标最常用MAE平均绝对误差误差的平均绝对值最直观。RMSE均方根误差误差平方后取平均再开方对大误差更敏感。MAPE平均绝对百分比误差误差占真实值的百分比方便不同量级的数据之间比较。from sklearn.metrics import mean_absolute_error, mean_squared_error mae mean_absolute_error(test[销量], mean_forecast) rmse np.sqrt(mean_squared_error(test[销量], mean_forecast)) mape np.mean(np.abs((test[销量] - mean_forecast) / test[销量])) * 100 print(fMAE: {mae:.2f}) print(fRMSE: {rmse:.2f}) print(fMAPE: {mape:.2f}%)一个合理的MAPE区间要看业务但在月度销量预测里如果MAPE在10%以内已经算很好的模型15%左右勉强能用超过25%就说明模型基本没有参考价值需要回去重新调参或者换方法。当然如果销量本身波动很大MAPE也会被个别极端值抬高所以建议同时看MAE和RMSE综合判断。6.4 画一张完整的“训练测试预测”对比图最后把训练集真实值、测试集真实值、预测值以及置信区间放在同一张图里plt.figure(figsize(12, 5)) plt.plot(train.index, train[销量], label训练集真实值) plt.plot(test.index, test[销量], label测试集真实值, markero) plt.plot(mean_forecast.index, mean_forecast, label预测值, markers) plt.fill_between(mean_forecast.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1], alpha0.3, label95%置信区间) plt.title(ARIMA预测结果对比) plt.legend() plt.grid(True) plt.show()这张图是给老板汇报时的核心输出。它能非常直观地展示出模型在最后几个月的表现预测曲线和真实曲线贴得近不近置信区间宽不宽。如果置信区间宽到覆盖了半个坐标系那就是在提醒你当前数据能给出的确定性就这些别期望太多。7. 完整代码汇总与参数速查7.1 一个脚本跑通ARIMA全流程我把上面所有步骤整理成一个可复制的完整脚本直接改数据路径就能跑import pandas as pd import numpy as np import matplotlib.pyplot as plt import warnings warnings.filterwarnings(ignore) from statsmodels.tsa.stattools import adfuller from statsmodels.graphics.tsaplots import plot_acf, plot_pacf from statsmodels.tsa.arima.model import ARIMA from statsmodels.stats.diagnostic import acorr_ljungbox from sklearn.metrics import mean_absolute_error, mean_squared_error # 1. 加载数据 df pd.read_csv(shampoo.csv, headerNone, names[销量]) df[日期] pd.date_range(start2022-01-01, periodslen(df), freqMS) df df.set_index(日期).astype(float) # 2. 画图观察 plt.figure(figsize(10, 4)) plt.plot(df.index, df[销量]) plt.title(洗发水月度销量) plt.grid(True) plt.show() # 3. 平稳性检验 result adfuller(df[销量]) print(原始序列p值:, result[1]) df[销量_diff] df[销量].diff().dropna() result_diff adfuller(df[销量_diff]) print(一阶差分后p值:, result_diff[1]) # 4. 网格搜索定阶 best_aic float(inf) best_order None for p in range(0, 5): for q in range(0, 5): try: model ARIMA(df[销量], order(p, 1, q)) fit model.fit() if fit.aic best_aic: best_aic fit.aic best_order (p, 1, q) except Exception: continue print(最优阶数:, best_order, AIC:, best_aic) # 5. 拟合与残差检验 model ARIMA(df[销量], orderbest_order) fit model.fit() print(fitr.summary()) resid fit.resid ljung acorr_ljungbox(resid, lags[6, 12], return_dfTrue) print(ljung) # 6. 训练测试切分 train df.iloc[:-6] test df.iloc[-6:] model ARIMA(train[销量], orderbest_order) fit_train model.fit() forecast_result fit_train.get_forecast(steps6) mean_forecast forecast_result.predicted_mean conf_int forecast_result.conf_int() # 7. 评估 mae mean_absolute_error(test[销量], mean_forecast) rmse np.sqrt(mean_squared_error(test[销量], mean_forecast)) mape np.mean(np.abs((test[销量] - mean_forecast) / test[销量])) * 100 print(fMAE{mae:.2f}, RMSE{rmse:.2f}, MAPE{mape:.2f}%) # 8. 画图 plt.figure(figsize(12, 5)) plt.plot(train.index, train[销量], label训练集) plt.plot(test.index, test[销量], label测试集真实值, markero) plt.plot(mean_forecast.index, mean_forecast, label预测值, markers) plt.fill_between(mean_forecast.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1], alpha0.3, label置信区间) plt.legend() plt.grid(True) plt.show()这个脚本的精髓在于把“定阶”和“评估”都自动化了你拿到自己的数据只需要改列名和时间频率。但我不建议完全黑盒式地跑脚本至少跑完要看一眼summary和残差图确认模型质量是经得起推敲的。7.2 ARIMA核心参数速查参数含义选择思路p自回归阶数看PACF截尾位置或网格搜索AIC最小d差分阶数看ADF检验能平稳就不再多差q移动平均阶数看ACF截尾位置或网格搜索AIC最小trend是否包含常数项一般让模型自动选择无需手调method参数估计方法默认即可出现收敛问题时再换7.3 从月度扩展到日度、周度数据如果你要预测的不是月度销量而是每日访问量或每周订单数流程完全一样改三处即可日期构造里的freq改成D或W-MON网格搜索的p和q范围可以适当扩大一点点因为高频率数据往往需要更多滞后期来捕捉短期依赖预测步数根据业务需求调整比如按天预测未来14天steps14。这里特别提醒一点日度数据中常常存在“周周期性”比如工作日高、周末低。如果你的数据有明显星期效应ARIMA是捕捉不到这种固定周期分量的应该用SARIMA并设置seasonal_periods7月度数据如果有年度效应则设置12。识别季节性最简单的办法就是画图看曲线是否在固定间隔重复出现波峰波谷。8. 常见问题与排查技巧实录8.1 报错Non-stationary starting autoregressive parameters这是我被问得最多的报错之一。很多新手一看到这个提示就以为自己的数据非平稳其实不然。这个报错通常说明模型的初始参数估计不太好尤其是在pq比较大或者数据方差很大时更容易出现。处理办法我按优先级列一下对销量做对数变换np.log(df[销量])压缩数据尺度。尝试换估计方法比如给fit()传methodinnovations_mle。减小p或q的取值范围降低模型复杂度。检查是否出现了极端离群值如果有优先处理离群值。注意这只是一个警告性质的报错有时候模型还是会出一个结果但AIC可能不够理想。千万别在报错后不闻不问直接拿结果去汇报。8.2 预测结果是一条水平直线很多初学者第一次做ARIMA预测跑出来发现预测值几乎一样就以为模型写错了。实际上这是ARIMA在长期预测中的正常现象模型预测步数拉长后预测会逐渐回归到序列的均值而且差分阶数越高这种趋势越明显。你可以把ARIMA看成一个衰减记忆系统它离当前点越远能依赖的历史信息越少预测自然趋于稳定。解决思路是缩短预测步数或者检查测试集里有没有模型完全没见过的突变。比如测试集最后一期突然因为大促翻倍而模型训练时从未见过促销因子那它当然预测不出这个高峰。ARIMA的职责是捕捉“常态下的规律”不是回答“意外事件”。8.3 数据量太少还要不要硬上ARIMA我的回答可能和很多教科书不一样如果你的历史数据不到20个点ARIMA大概率表现不如简单方法。这不是说ARIMA代码有问题而是在小样本下它的参数估计方差太大定阶会很不稳定。我自己做项目时会做一个小实验拿前80%的数据训练用不同的模型跑一遍如果ARIMA比“用上个月值预测下个月”的朴素方法强不了多少那就果断用朴素方法。模型是为了解决业务问题而存在的不是为了看起来高级。8.4 定阶结果不稳定怎么办网格搜索选出的最优阶数可能随着你更换测试集比例而改变这是正常现象。我的习惯是不要只盯着AIC最小的那组参数而是把AIC排名前5的组合都列出来观察它们的预测误差。如果好几个组合的AIC都差不多但预测结果差异很大说明模型本身不稳定此时优先选择参数更少、更简单的组合也就是遵循奥卡姆剃刀原则。在业务实践中一个解释起来更容易、行为更稳定的模型往往比一个精度只高一点点但复杂度成倍增加的模型更有价值。另外如果你发现优化出的p和q都比较大比如p4、q4而数据只有36个月强烈建议把参数范围缩小。模型越复杂需要的数据就越多参数过拟合风险越高。用36个点去拟合一个8参数的模型结果基本经不起推敲。8.5 数据里有缺失值怎么办ARIMA不支持缺失值。处理办法有两种如果缺失点不多用前后月的均值插值如果缺失的是整段月份则建议检查是否能把数据重采样到更低频率比如月度数据缺了两个月可以尝试改成季度数据建模。千万不要直接在缺失的位置填0那会把模型带偏。写到这儿ARIMA从数据准备到参数定阶、模型拟合、诊断、预测评估的完整链路就算走完了。这套流程我在实际项目中反复用过很多次越是新手越容易在平稳性检验和定阶上纠结太久其实多跑几组对比、多看残差和预测图手感很快就出来了。下一次你再遇到一列按月、按天排好的销售或运营数据就能有条不紊地先画图、再检验、再定阶、最后给出带置信区间的预测结果。
返回列表