Python ARIMA时间序列销量预测:从平稳性检验到滚动预测实战

发布时间:2026/9/28 12:57:40
Python ARIMA时间序列销量预测:从平稳性检验到滚动预测实战 简介这份资源是面向Python数据分析初学者、毕业设计及课程设计学生的ARIMA时间序列销量预测完整方案帮助解决从数据平稳化处理、模型定阶到预测检验的全流程建模问题。包内共16个文件以py脚本、png图表、zbak备份、xls与xlsx数据表及md说明为主压缩包约255KB涵盖建模代码、销量时序图、差分后自相关与偏相关图、上线效果图等关键素材。资源采用每月上中下旬三次预测策略将月上旬与中旬实际销量作为先验知识提升当月预测精度并借助statsmodels完成窗口选择、自动定阶与平稳性检测。目前已有78人学习下载适合需要完整赛题方案、可运行代码与图表参考的读者便于快速复现实验、理解ARIMA建模思路并完成论文或作业撰写。1. 销量预测这件事为什么 ARIMA 依然是绕不开的起点电商大促前两周运营把过去 18 个月的日销量表甩过来问下个月能卖多少。你打开一看数据有缺失、有促销尖峰、有春节断崖第一反应可能是上 LSTM。但真实情况是样本量只有五百多行特征工程还没做业务方明天就要一个能解释的区间。这时候 ARIMA 反而是最稳的选择——它不需要大量数据参数有明确的统计含义残差可以检验预测区间能直接给业务方看。Python 做 ARIMA 时间序列销量预测模型核心链路其实就四步把销量整理成带时间索引的序列、做平稳性检验和差分、定阶拟合、滚动预测并评估。这套流程在 statsmodels 里都有现成实现难点不在写代码而在每个环节的参数判断和边界处理。这篇文章面向两类人一类是刚学完 Python 基础、想找一个完整数据分析项目练手的另一类是已经在做销量预测、但模型效果不稳定想回头补统计基础的。下面按真实落地顺序拆开讲每一步都给可复现的代码和参数说明。2. 数据准备与平稳性销量序列能不能直接喂给 ARIMA2.1 销量数据的三个硬性要求ARIMA 对输入序列有隐含假设很多人翻车就翻在这里。第一时间索引必须等间隔。日销量就是每天一条如果某天没卖出东西就缺行必须补零而不是跳过否则差分后的间隔就乱了。第二序列要按时间升序排列索引最好是 pandas 的 DatetimeIndex这样 resample 和 shift 才不会出错。第三单条序列长度建议不少于 50 个观测点低于这个量级参数估计的方差会大到没法用。我一般拿到原始表先做三件事解析日期列、按日期聚合去重、用 asfreq 补齐缺失日期。补齐后缺失的销量填 0 还是插值要看业务含义——零售日销缺记录通常是当天没交易填 0 合理如果是传感器采集缺失才考虑插值。import pandas as pd import numpy as np # 原始数据date 列是字符串sales 是当日销量 df pd.read_csv(sales.csv, parse_dates[date]) df df.sort_values(date).drop_duplicates(date) # 设为时间索引补齐缺失日期 s df.set_index(date)[sales].asfreq(D) # 缺记录按业务含义填 0 s s.fillna(0).astype(float) print(s.index.freq) # Day确认频率已识别 print(len(s), s.isna().sum())这段代码的关键在 asfreq(D)它把不连续的日期索引强制变成每日连续缺失位置引入 NaN再由 fillna(0) 决定填充策略。parse_dates 保证 date 是 datetime 类型否则 set_index 后频率推断会失败。drop_duplicates 防止同一天多条记录导致索引重复重复索引在后续差分时会直接报错。2.2 平稳性检验ADF 怎么看、p 值多大才算稳ARIMA 的 I 就是差分阶数差分几次取决于序列平稳性。判断平稳性最常用 ADF 检验原假设是「序列存在单位根即不平稳」。p 值小于 0.05 就拒绝原假设认为平稳。但实操里不能只看 p 值还要看检验统计量和临界值的关系以及序列图有没有明显的趋势或季节波动。from statsmodels.tsa.stattools import adfuller def adf_report(series, nameseries): result adfuller(series.dropna(), autolagAIC) print(f{name} ADF统计量: {result[0]:.4f}) print(f{name} p值: {result[1]:.4f}) for k, v in result[4].items(): print(f 临界值 {k}: {v:.4f}) return result[1] p0 adf_report(s, 原始销量) s_diff1 s.diff().dropna() p1 adf_report(s_diff1, 一阶差分)autolagAIC 让 statsmodels 自动选择滞后阶数比手动指定 maxlag 更省事。如果原始序列 p 值大于 0.05做一阶差分再检验一阶差分还不稳就做二阶。但差分不是越多越好每差一次就丢一个观测点而且过差分会让序列方差变大、引入负相关。销量数据一般一阶差分就够带明显年度周期的才考虑季节差分。注意ADF 对结构性突变很敏感。如果序列中间有促销导致的水平跳变ADF 可能误判为不平稳这时候要先做突变点处理或分段建模而不是无脑差分。3. 定阶与拟合p、d、q 三个参数到底怎么定3.1 用 ACF 和 PACF 图做初步定阶d 由上一章的差分次数确定剩下 p 和 q 看自相关函数 ACF 和偏自相关函数 PACF。经验规则是ACF 拖尾、PACF 截尾用 AR(p)p 取 PACF 最后一个显著非零的滞后阶ACF 截尾、PACF 拖尾用 MA(q)q 取 ACF 最后一个显著滞后两个都拖尾用 ARMA(p,q)这时候图上看不出来得靠信息准则搜。import matplotlib.pyplot as plt from statsmodels.graphics.tsaplots import plot_acf, plot_pacf fig, axes plt.subplots(2, 1, figsize(10, 6)) plot_acf(s_diff1, lags30, axaxes[0]) plot_pacf(s_diff1, lags30, axaxes[1], methodywm) plt.tight_layout() plt.savefig(acf_pacf.png, dpi120)lags 一般取序列长度的十分之一到四分之一日销量五百条取 30 到 50 都行。methodywm 是偏自相关的估计方法样本量不大时比默认方法稳定。看图时关注蓝色置信带以外的柱子带内的小波动不用管否则容易过拟合。3.2 网格搜索加 AIC 定阶比肉眼靠谱图只能给个范围真正定阶我习惯用网格搜索配合 AIC。AIC 同时惩罚拟合优度和参数个数值越小越好。statsmodels 的 ARIMA 在拟合失败时会抛异常所以循环里要 try 住把不收敛的组合跳过。import warnings from statsmodels.tsa.arima.model import ARIMA warnings.filterwarnings(ignore) best_aic, best_order np.inf, None for p in range(0, 4): for q in range(0, 4): try: model ARIMA(s, order(p, 1, q)) res model.fit() if res.aic best_aic: best_aic, best_order res.aic, (p, 1, q) except Exception: continue print(最优阶数:, best_order, AIC:, round(best_aic, 2))order 里的 d 固定为 1因为前面已经确认一阶差分平稳。p 和 q 搜到 3 基本够用再大容易过拟合且训练变慢。fit() 默认用最大似然数据量大时可以加 method_kwargs 控制优化器。搜完之后不要只看 AIC还要把最优模型的残差拿出来做白噪声检验残差还有自相关说明阶数没定够。3.3 拟合结果怎么读哪些参数必须看拟合完的 summary 信息量很大但新手容易只看 AIC。必须看的还有三项系数的显著性P|z| 小于 0.05、残差的 Ljung-Box 检验 p 值大于 0.05 说明残差接近白噪声、以及根是否在单位圆外保证模型平稳可逆。res ARIMA(s, orderbest_order).fit() print(res.summary()) from statsmodels.stats.diagnostic import acorr_ljungbox lb acorr_ljungbox(res.resid, lags[10], return_dfTrue) print(lb)如果某个系数不显著可以考虑去掉对应阶数重新拟合。Ljung-Box 的 lags 取 10 或 20p 值小于 0.05 说明残差还有结构没被模型抓住需要加阶或换模型。残差图也要看一眼有没有明显的异方差或离群点这些都会影响预测区间的可靠性。4. 预测与评估滚动预测才是真实场景的照妖镜4.1 静态预测和滚动预测的区别很多人拟合完直接 forecast(30) 就交差了这是静态预测用的是训练集末尾的信息外推。真实业务里模型是每天更新的所以评估必须用滚动预测每次用历史数据预测下一天然后把真实值加进历史再预测下一天。这样得到的误差才反映上线后的表现。train_size int(len(s) * 0.8) train, test s[:train_size], s[train_size:] history list(train) preds [] for t in test: model ARIMA(history, orderbest_order).fit() yhat model.forecast()[0] preds.append(yhat) history.append(t) # 把真实值并入历史滚动前进 preds pd.Series(preds, indextest.index)这段循环每步都重新拟合计算量大但最接近真实。如果数据很长可以改成固定参数只更新状态但销量预测数据量通常不大重拟合完全扛得住。history.append(t) 用的是真实值而不是预测值这叫一步滚动评估的是模型在已知前一天真实销量后的预测能力。4.2 三个评估指标和它们的适用场景MAE、RMSE、MAPE 是最常用的三个。MAE 直观单位跟销量一致RMSE 对大误差惩罚重关心极端偏差时用它MAPE 是百分比跨品类对比方便但销量接近 0 时会爆炸这时候改用 sMAPE 或直接看 MAE。from sklearn.metrics import mean_absolute_error, mean_squared_error mae mean_absolute_error(test, preds) rmse np.sqrt(mean_squared_error(test, preds)) mape np.mean(np.abs((test - preds) / test.replace(0, np.nan))) * 100 print(fMAE{mae:.2f} RMSE{rmse:.2f} MAPE{mape:.2f}%)test.replace(0, np.nan) 是为了避开除零代价是 MAPE 会忽略真实值为 0 的点所以报告 MAPE 时要说明剔除了多少点。评估完把预测值和真实值画在一张图上肉眼看一下相位有没有滞后、尖峰有没有被削平这比单看数字更能发现问题。4.3 预测区间给业务方的后悔药点预测不够用业务方要的是「大概在什么范围」。ARIMA 的 get_forecast 能直接给置信区间宽度随预测步长增加而变宽这符合直觉——预测越远越不确定。forecast_res res.get_forecast(steps30) mean forecast_res.predicted_mean ci forecast_res.conf_int(alpha0.05) # 95% 区间 print(mean.head()) print(ci.head())alpha0.05 对应 95% 置信区间要 90% 就设 0.1。区间宽度受残差方差影响如果残差有异方差区间会失真这时候可以考虑对销量取对数再建模预测完再指数还原。5. 避坑与排查销量预测里最常见的五个翻车现场5.1 现象预测曲线整体平移系统性偏高或偏低原因通常是差分还原时漏掉了原始水平。ARIMA 建模的是差分后的序列预测值需要累加回原始尺度statsmodels 的 forecast 会自动处理但如果你手动做了差分又手动还原很容易漏掉最后一个训练值的基准。解决方法是直接用原序列拟合、让模型内部处理差分或者手动还原时确认累加起点是训练集最后一个真实值。5.2 现象AIC 很小但预测一塌糊涂这是过拟合的典型。p 或 q 定得太大模型把训练集的噪声也学进去了样本外就崩。排查方法是看残差 Ljung-Box 是否通过、系数是否显著以及把 p、q 限制在 3 以内重搜。销量数据信噪比低阶数宁小勿大。5.3 现象遇到促销尖峰预测完全跟不上ARIMA 是线性模型对突发尖峰没有外生解释能力。如果促销有规律可以加季节项或 SARIMA如果促销时间不固定应该把促销标记作为外生变量改用 SARIMAX 的 exog 参数。硬用 ARIMA 拟合尖峰只会让残差方差变大拖累整体预测。5.4 现象MAPE 高得离谱检查发现真实值有 0销量为 0 的天数不少时MAPE 会被除零放大。解决方法是改用 MAE 或 sMAPE或者在计算前过滤掉真实值为 0 的点并说明。不要为了指标好看去改数据那是在骗自己。5.5 现象模型每次跑结果都不一样ARIMA 的优化器有随机初值数据量小或阶数高时可能收敛到不同局部最优。解决方法是固定随机种子、多跑几次取 AIC 最小的或者换用更稳定的优化方法。如果结果波动很大说明数据本身信息量不足该考虑加特征或换模型了。6. 把 ARIMA 用稳的一个习惯残差监控与滚动重训模型上线不是终点。我自己的习惯是每次预测后把残差存下来按周看残差的均值和方差有没有漂移。销量预测最怕的是业务模式变了但模型没跟着变残差监控就是最便宜的报警器。具体做法是维护一个残差队列用滚动窗口算残差的标准差超过历史分位数就触发重训。# 残差监控滚动窗口标准差超过阈值就告警 resid_series pd.Series(res.resid) roll_std resid_series.rolling(14).std() threshold roll_std.quantile(0.95) if roll_std.iloc[-1] threshold: print(残差波动异常建议重新定阶或重训)rolling(14) 是两周窗口阈值取历史 95 分位这两个参数按业务节奏调——日销用 14 天周销用 8 周。重训频率不用太高数据量小的时候每月一次就够大促前手动触发一次。另一个实用技巧是给预测值加一个简单的偏差校正。滚动预测跑一段时间后统计预测值和真实值的平均偏差如果系统性偏高就减掉这个偏差。这不是什么高级方法但在业务侧往往比调模型参数见效快。最后说个我踩过的坑早期我总想把所有品类用一个模型批量跑结果每个品类的平稳性和周期都不一样参数根本没法统一。后来改成按品类聚类、分组定阶工作量大了但效果稳了。ARIMA 不是万能锤它适合的是单序列、中短周期、有统计规律可循的销量预测。数据够多、特征够丰富的时候LSTM 那类模型确实有优势但前提是你得先把 ARIMA 这套基线跑通不然连模型有没有变好都判断不了。希望帮到你。本文还有配套的精品资源点击获取