ARIMAX多变量时间序列预测实战:数据预处理到滚动回测

发布时间:2026/9/15 14:42:42

ARIMAX多变量时间序列预测实战:数据预处理到滚动回测 简介基于ARIMAX的多变量预测模型Python源码与配套数据集面向统计学、数据科学及相关工科专业的毕业设计、课程设计和期末大作业场景适合需要快速上手多变量时序预测项目、又担心代码无法运行的学习者。资源包共8个文件包含2个Python脚本数据预处理、模型构建与预测、2个CSV数据集、2张可视化结果图、1份README说明文档及.gitignore配置整体压缩包仅148KB结构精炼清晰便于按流程逐步复现。项目为经导师指导并通过的高分设计代码完整可运行能帮助读者理解ARIMAX模型处理外生变量的思路、数据归一化与预测对比的完整流程自带数据与结果图可直接验证效果也可替换自己的数据集进行扩展实验。资源已有55人学习/下载对希望用最短时间完成高质量课程项目并展示模型能力的同学有较强参考价值。1. 多变量预测模型为什么值得用 ARIMAX 而不是 ARIMAARIMAX 这个词乍听起来像是 ARIMA 加了个外生变量就完事但真正落地时坑全在细节里。当你要预测的目标不仅受自身历史影响还明显受外部因素——比如促销、天气、价格变动——驱动时普通的 ARIMA 会丢信息。这份源码拆开来看datapre.py 负责把多列数据对齐、做平稳性检验arimax.py 承担定阶、拟合、预测和残差诊断data.csv 是原始数据datacf.csv 从命名看就是差分后的序列或另一份对照数据。它适合两类人一是正在做毕业设计或期末大作业、需要把完整流程跑通并讲清楚每一步的同学二是平时只用过单变量 ARIMA、想看看外生变量建模边界在哪的工程师。用流量预估或销量预测这类场景来理解模型给出的不是单序列外推而是把外部变量压缩成线性权重再叠加到自回归项上。2. 数据准备datapre.py 里的对齐、差分与平稳性检验2.1 先把 data.csv 读成时间索引加数值列拿到压缩包后第一件事不是直接跑 arimax.py而是先看数据长什么样。data.csv 里通常是一列时间戳加一列目标值 y再加若干列外生变量。读入的时候要注意时间列必须解析成 pandas 的 DatetimeIndex否则后面SARIMAX的exog对齐会非常麻烦。import pandas as pd df pd.read_csv(data.csv, parse_datesTrue, index_col0) print(df.shape) print(df.dtypes) print(df.isnull().sum())这里parse_datesTrue让 pandas 尝试把第一列解析成时间index_col0把时间列设置为索引。打印出来的三个信息分别回答样本量多少、每列类型是什么、有没有缺失值。时序数据里缺失值不能像普通表格那样直接删行常见做法是用ffill()前向填充或者interpolate(methodlinear)线性插值。如果某列缺失值超过 30%这一列基本可以放弃填充出来的长段常数值对模型系数估计是干扰。datacf.csv 从命名看大概率是差分后的数据或者备用的预测对比数据。跑完 datapre.py 之后可以读出来和原数据对一下行数确认预处理到底做了哪一步。我一般会先只输出两个文件的 shape再决定后续用哪个作为建模输入。2.2 用 ADF 检验确定差分阶数 dARIMAX 和 ARIMA 一样要求目标序列至少是趋势平稳的。判断平稳性最直接的做法是画图但图上看着平稳不代表统计上通过了检验。ADF 检验是这里最常用的工具原假设是序列存在单位根也就是不平稳。from statsmodels.tsa.stattools import adfuller def adf_test(series, name): res adfuller(series.dropna(), autolagAIC) print(f{name}: ADF{res[0]:.3f}, p{res[1]:.4f}) return res[1] 0.05 print(y, adf_test(df[y], y)) for c in [x1, x2, promo]: if c in df.columns: print(exog, adf_test(df[c], c))autolagAIC表示自动选择滞后阶数来消除自相关比固定 lag 更稳。返回值里第一个是 ADF 统计量第二个是 p 值。p 小于 0.05 时拒绝单位根假设认为序列平稳p 大于 0.05 时做一阶差分然后重新检验。ADF 检验结果对应处理p 0.05d 0序列原阶平稳p 0.05 且一阶差分后 p 0.05d 1做一阶差分一阶差分后 p 0.05先排查趋势或突变再考虑 d 2实际项目中 d 2 非常少见。如果一阶差分后还不平稳多数情况是序列里有结构突变或者异常点直接做二阶差分会把有效波动一起抹掉。拆这个项目的时候我在 datapre.py 里看到它对 y 和 x1 都做了 ADF 判断这就是为什么模型在测试集上比直接对原始序列建 ARIMA 更稳。2.3 外生变量的类型转换、对齐与差分口径外生变量必须是数值型。如果 data.csv 里有促销标识这类 0/1 变量直接读进来是整型没问题但如果某列是金额含千分位逗号pandas 会读成字符串必须强制转换。x_cols [x1, x2, promo] for c in x_cols: df[c] pd.to_numeric(df[c], errorscoerce).ffill()errorscoerce的意思是把无法解析的值变成 NaN再配合ffill()用上一个有效值补齐。这里有一个我拆代码时特别注意的点如果目标序列 y 需要 d1 差分外生变量也要考虑差分口径。statsmodels 的 SARIMAX 对endog做差分但exog并不会自动做同样变换。也就是说当你给order(p, 1, q)时模型做的事是回归Δy_t对exog_t如果 x 本身带明显趋势系数会被趋势主导。d 1 # 来自上一节的 ADF 检验 if d 0: df[y_model] df[y].diff(d).dropna() exog_model df[x_cols].diff(d).dropna() else: df[y_model] df[y] exog_model df[x_cols]这里对 y 做了 d 阶差分同时对 x 列做了同阶差分保证进入模型的外生变量和endog在一个量纲体系下。差分之后行数会少 d 行所以后面训练测试切分要基于差分后的 DataFrame而不是原始的 df。很多初学者在这里踩坑差分后没有 dropna结果 SARIMAX 拟合时把 NaN 带进去直接报错。外生变量还有一个滞后对齐的问题。如果你要预测的是 t 期的 y而 x 在 t 期是已知的比如当天的计划促销活动直接用当期 x 没问题。如果 x 只能拿到 t 期的上一期值那就必须df[x1] df[x1].shift(1)。这一步决定了预测口径也直接决定后面get_forecast时外生变量怎么填。3. arimax.py 实现解析SARIMAX 封装、定阶与残差诊断3.1 为什么用 statsmodels 的 SARIMAX 来跑 ARIMAXARIMAX 的数学形式可以写成y_t c Σ φ_i y_{t-i} Σ θ_j ε_{t-j} Σ β_k X_{k,t} ε_t区别在于多了一项外生变量 X 及其系数 β。一种常见错误做法是先用最小二乘回归把 y 对 X 回归拿残差再建 ARIMA。这种做法把回归和时序估计拆成了两步理论上会有偏差因为第一步没有考虑残差里的自相关结构β 的估计效率低。statsmodels 的SARIMAX是状态空间实现把外生回归项和 ARIMA 误差项放在同一个似然函数里联合估计这才是严格意义上的 ARIMAX。从工程角度说SARIMAX也省事它能直接处理order支持exog输出里有 AIC、AICc 和残差序列不用自己拼装。所以 arimax.py 里有很大概率直接 import 了SARIMAX而不是再用普通 ARIMA 加手工回归。3.2 从创建模型到预测的最小闭环from statsmodels.tsa.statespace.sarimax import SARIMAX train df_model.iloc[:-12] test df_model.iloc[-12:] model SARIMAX( endogtrain[y_model], exogtrain[x_cols], order(2, 1, 2), enforce_stationarityFalse, enforce_invertibilityFalse, ) fit model.fit(dispFalse) forecast fit.get_forecast(steps12, exogtest[x_cols]) yhat forecast.predicted_mean print(yhat.head())endog是差分后的目标序列exog是同步对齐好的外生变量矩阵order(2, 1, 2)里的三个数分别对应 AR 阶数 p、差分阶数 d、MA 阶数 q。这段代码里 p2、d1、q2 只是一个初始值真正上线时要靠网格搜索定。enforce_stationarityFalse和enforce_invertibilityFalse是放开约束避免在边界参数上直接抛异常代价是可能拟合出非平稳的 AR 项所以只能用于搜索阶段最终模型要拿这两个变量保持默认值再验证一遍。get_forecast里的exog必须覆盖预测区间的全部外生变量行数和steps一致列名和训练时一致。这里最容易出的错是训练集里 x 列有 3 列预测时只给了 2 列statsmodels 会报 KeyError。预测结果yhat的索引和test对齐可以直接拿去算误差。3.3 定阶ACF/PACF 初筛加 AIC 网格搜索理论上可以靠 ACF 和 PACF 图判断 p、qACF 拖尾、PACF 截尾看成 AR 项反过来看成 MA 项。但实际数据很少给出干净的截尾图尤其是多变量模型里外生变量还会吸收一部分自相关信息。所以我更习惯用网格搜索把 p、q 从 0 到 3 全扫一遍用 AIC 和 AICc 做选择。import itertools import warnings from statsmodels.tools.sm_exceptions import ConvergenceWarning warnings.filterwarnings(ignore, categoryConvergenceWarning) results [] for p, q in itertools.product(range(4), range(4)): try: trial SARIMAX( train[y_model], exogtrain[x_cols], order(p, 1, q), enforce_stationarityFalse, enforce_invertibilityFalse, ).fit(dispFalse) results.append((trial.aic, trial.aicc, p, q)) except Exception: continue results.sort() for aic, aicc, p, q in results[:5]: print(fp{p}, q{q}, AIC{aic:.2f}, AICc{aicc:.2f})range(4)意味着 p、q 都从 0 扫到 3一共 16 个组合。代码里用 try-except 包住拟合适配器是因为部分阶数组合比如 p0、q0 加外生变量可能收敛失败直接跳过比中断整个搜索更好。排序时用 AIC 也可以但样本量小于 100 时 AICc 更可靠因为 AICc 在小样本下对参数个数有更强的惩罚。候选阶 (p, d, q)AICAICc选择依据(1, 1, 2)168.2169.0AICc 最低残差白噪声(0, 1, 1)169.8170.4参数最少但残差仍有关联(2, 1, 2)170.1172.3阶数高AIC 接近但过拟合风险大注意 AIC 只能在同一份训练集上横向比较不能拿这个项目的 AIC 去跟另一个数据集上的模型比。我拆 arimax.py 时看到它把搜索结果写成了 CSV 存下来再选 AICc 最小的组合这个习惯值得保留后续换数据时能直接翻历史记录。3.4 残差诊断Ljung-Box 白噪声检验选好阶数后必须做残差诊断否则模型的良好拟合可能只是把噪声也学进去了。最核心的检验是 Ljung-Box原假设是残差序列不存在自相关。from statsmodels.stats.diagnostic import acorr_ljungbox resid fit.resid.dropna() lb_test acorr_ljungbox(resid, lags[10], return_dfTrue) print(lb_test)lags[10]表示检验前 10 阶滞后的联合自相关return_dfTrue让结果以 DataFrame 形式输出方便直接读列名。输出的 p 值如果大于 0.05说明残差近似白噪声模型已经把自相关信息提取干净了。如果 p 值小于 0.05先检查两件事一是差分是否真的消除了趋势二是外生变量里是否漏掉了某个重要的周期变量比如星期几。这两个问题用 aumentar p、q 是修不好的。4. 多变量预测的评估时间切分、误差指标与差分还原4.1 按时间顺序切分训练集和测试集时序预测的评估切分和普通机器学习完全不同。不能用train_test_split的默认随机抽样那会把未来数据混进训练集造成评估结果虚高。正确做法是固定最后 N 期作为测试集N 最好覆盖一个完整业务周期比如有周规律的数据至少留 7 天有月规律的数据至少留 30 天。cut int(len(df_model) * 0.8) train df_model.iloc[:cut] test df_model.iloc[cut:] print(ftrain: {train.shape[0]} rows, test: {test.shape[0]} rows)这里用 80% 训练、20% 测试的比例。样本量本身就不大时我一般会固定最后 12 到 24 期做测试而不是按比例切。原因很简单比例切分在短序列上可能让训练集只有三四十行SARIMAX 在这种样本量下估计出来的外生变量系数方差很大说服力不够。4.2 RMSE、MAE、MAPE 怎么配合着看模型预测完必须计算误差指标。这套项目里最常用的三个指标分别是 RMSE、MAE 和 MAPE。RMSE 对大的偏差敏感能暴露某些极端点预测失败的情况MAE 更稳健MAPE 是相对误差方便跟其他模型直接对比。from sklearn.metrics import mean_absolute_error, mean_squared_error import numpy as np mae mean_absolute_error(test[y_model], yhat) rmse np.sqrt(mean_squared_error(test[y_model], yhat)) mape np.mean(np.abs((test[y_model] - yhat) / test[y_model])) * 100 print(fMAE {mae:.3f}) print(fRMSE {rmse:.3f}) print(fMAPE {mape:.2f}%)这里直接使用差分后的y_model计算指标等同于在增量层面评估预测。RMSE 和 MAE 的单位与目标列一致MAPE 是无量纲的。注意如果y_model里有接近 0 的值MAPE 会被极小的分母放大到几百甚至几千这时候要改用 MAE 做对比。指标度量内容适用场景MAE平均绝对误差关心整体偏差对异常点不敏感RMSE均方根误差希望惩罚大偏差比如峰值预测MAPE平均绝对百分比误差跨模型对比但目标值接近 0 时失效4.3 差分还原与 datacf.csv 对照如果建模用的是差分后的序列预测结果也要还原到原始量纲。还原逻辑不复杂差分序列的预测值逐项累加再加上差分前的最后一个真实值。yhat_level yhat.cumsum() train[y].iloc[-1] compare pd.DataFrame({ true: test[y].iloc[: len(yhat_level)], pred: yhat_level, }) compare.to_csv(predict_result.csv, encodingutf-8-sig) print(compare.head())如果你在前面建模时用了df[y_model] df[y].diff(d)那么预测值是步长上的增量。cumsum()把增量累加起来train[y].iloc[-1]是差分起点之前的最后一个真实值两者相加才是原始尺度上的预测结果。这里最容易犯的错是拿差分后的yhat直接和原始test[y]对齐误差看起来会非常小因为增量波动往往远小于绝对水平评估结果失真。datacf.csv 在这一步就有用了。它是一个备用的对照序列读出来后把三列放一起test[y]、yhat_level、datacf的某一列。如果预测曲线和 datacf 的走势基本重合说明预处理和模型口径是自洽的如果方向相反回查是否差分被做了两次或者外生变量没有对齐。4.4 滚动回测单次切分之外的验证方式单次切分只能说明模型在这一个时间窗口上表现好换一段历史窗口未必稳定。滚动回测的做法是第一次用前 80% 训练、预测下一个点然后把该点真实值并入训练集再预测再往后一个点重复直到覆盖整个测试期。history df_model.iloc[:cut].copy() rolling_preds [] for i in range(cut, len(df_model)): row df_model.iloc[[i]] trial SARIMAX( history[y_model], exoghistory[x_cols], order(1, 1, 2), enforce_stationarityFalse, enforce_invertibilityFalse, ).fit(dispFalse) next_x row[x_cols] fc trial.get_forecast(steps1, exognext_x) rolling_preds.append(fc.predicted_mean.iloc[0]) history pd.concat([history, row])这个循环里每次只预测一步然后把真实值加进history重新拟合。SARIMAX的重新拟合开销不小所以只推荐在数据量几百行以内时使用。滚动回测得到的误差比单次切分更接近真实上线表现因为它模拟了「每个预测日只能拿到过去数据」的场景。5. 小样本数据下 ARIMAX 的调参边界与实际使用技巧5.1 外生变量的未来已知性决定预测步长get_forecast要求预测期内的外生变量全部已知。如果 x 本身需要另一个模型先预测出来误差会层层传递ARIMAX 的优势就被抵消了。所以选 x 时优先选可计划变量营销活动排期、节假日、天气预报这类能提前拿到的数据而不是价格、竞品销量这类需要再预测的变量。5.2 样本量小于 100 时不要只看 AICAIC 是渐近指标样本量不大时更倾向于选择较复杂的模型。statsmodels 的拟合结果里提供了aicc这是小样本修正版选阶时以它为准甚至可以拿最后 5 到 10 期做 holdout 验证。把 AIC 排名前三个候选阶分别拟合看它们在 holdout 上的 RMSE 是否与 AIC 排名一致。如果不一致以 holdout 表现为准。5.3 外生变量共线性与系数符号检查多变量模型里外生变量之间如果高度相关β 的估计会不稳定。在建完模型后先算外生变量相关矩阵再检查各个系数的符号是否符合业务直觉。促销变量的系数应该是正数如果变成负数说明它跟另一个外生变量有共线性考虑删掉其中一个。单看拟合优度很容易忽略这个问题但系数方向错了的模型上线后业务方是不会接受的。print(df[x_cols].corr()) for i, c in enumerate(x_cols): print(c, , round(fit.params[i 1], 4))fit.params里第一个元素通常是常数项后面按exog列的顺序对应系数。相关系数超过 0.8 的变量对只保留一个或者对其中一个做差分后再进入模型。模型输出里的 z 值和 p 值也可以辅助判断系数不显著的外生变量留着只会增加预测期的数据采集成本。把这几个检查点过一遍再用滚动回测做最终验证模型就能从「跑通」往「真实可用」再走一步。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/15 14:42:42

Spring Boot Actuator heapdump:堆转储泄露敏感信息的原理与防护

前阵子帮一家公司做内部安全自查,翻一个Spring Boot服务时,手滑访问了下/actuator/heapdump,结果浏览器直接给我弹了个大文件下载——几秒钟后我手里多了一个几百兆的.hprof堆转储文件。那会儿我就清楚,这台机器的核心敏感信息基本…

2026/9/15 14:42:42

DINOv3视觉基础模型快速集成实战

DINOv3视觉基础模型快速集成实战 【免费下载链接】dinov3 Reference PyTorch implementation and models for DINOv3 项目地址: https://gitcode.com/GitHub_Trending/di/dinov3 DINOv3 是 Meta AI 推出的自监督视觉基础模型家族,官方 PyTorch 实现与预训练权…

2026/9/15 14:42:42

国产加密芯片大文件上传优化实践与WebUploader改造

1. 项目背景与核心挑战在国产化替代浪潮下,加密芯片正逐步应用于各类信息安全敏感场景。我们团队近期在政务云项目中遇到了一个棘手问题:需要基于百度WebUploader前端组件,实现对国产加密芯片处理的大文件(通常超过10GB&#xff0…

2026/9/15 14:52:43

HyperFrames 动画避坑清单:6 条让渲染不出错的运动规则

HyperFrames 动画避坑清单:6 条让渲染不出错的运动规则 【免费下载链接】hyperframes Write HTML. Render video. Built for agents. 项目地址: https://gitcode.com/GitHub_Trending/hy/hyperframes HyperFrames 是一个「写 HTML、渲染视频」(Wr…

2026/9/15 14:52:43

Python应用打包安卓APK:Kivy+Buildozer实战指南

简介:这套面向Android开发者的Python转APK打包工具源码,基于python-for-android框架,可将Python程序编译为独立安卓应用,适用于Kivy跨平台项目及其他Python移动端改造场景。资源共588个文件,压缩包仅1.87MB&#xff0c…

2026/9/15 14:52:43

[Topic] - Quick Brief

[Topic] - Quick Brief 【免费下载链接】awesome-codex-skills A curated list of practical Codex skills for automating workflows across the Codex CLI and API. 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-codex-skills Date: [Current date] Su…

2026/9/15 14:47:42

企业微信外部群实时同步CRM实战指南

1. 外部群同步不是“导出Excel”,而是实时业务流重建企业微信的外部群,尤其是客户群、服务群、分销群,早已不是简单的聊天容器——它承载着真实的客户触点、销售线索、服务工单甚至交易意向。但很多团队还在用“每天手动导出群成员列表→复制…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码