ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ARIMAX多变量预测实战:外生变量构造与Python实现

ARIMAX多变量预测实战:外生变量构造与Python实现 简介基于ARIMAX的多变量预测模型Python源码与配套数据集面向需要处理含外部回归变量的时间序列预测任务的数据分析人员及Python开发者。资源围绕ARIMAX模型展开兼顾数据预处理与建模实现可帮助读者理解多变量输入下如何构建稳健的预测流程。包体共7个文件包含2个Python脚本分别对应数据预处理与ARIMAX建模、2个CSV数据集供实验调用、2张说明图片及1份Markdown说明文档压缩包大小约146KB结构紧凑适合快速上手。目前已有408人学习使用可作为课程作业、项目验证或算法对比的参考实现。通过源码注释与配套数据读者能够直接运行并观察数据预处理、模型拟合与结果展示的完整链路同时Markdown文档提供必要的使用说明降低了理解与复现门槛。1. 为什么单拿ARIMAX做多变量预测而不是直接上深度学习做过门店销量预测的工程师大概都经历过这种翻车只把历史销量喂给 ARIMA 时平时拟合得挺好的模型一到节假日就彻底失效误差拉出一条长长的上扬曲线。问题不在 ARIMA 本身而是你根本没告诉它节假日要来了外部信息被完全丢掉了。ARIMAX带外生变量的 ARIMA就是为了解决这件事而存在的它在保留差分平稳化能力的同时额外接受一组与目标序列同步的外生变量把节假日标记、温度、促销开关这些信息作为回归项接入模型。这个 zip 方案把 ARIMAX 在多变量场景下的完整链路都装了进去——Python 源码负责数据对齐、模型训练、预测还原配套数据集让你不需要到处找数据就能对照着复现。它的受众很明确正在做销售、客流、能源负荷预测的工程师以及想让预测结果不靠运气、能说清外生变量真贡献的团队。2. ARIMAX原理与选型外生变量到底如何进入ARIMA2.1 从ARIMA到ARIMAX一个回归项把外部因素接进来ARIMA(p,d,q) 做的事是对目标序列做 d 阶差分拿到平稳序列再用 p 阶自回归和 q 阶移动平均描述这个平稳序列的时域结构。换句话说ARIMA 只关心目标序列自己过去的值和过去的误差。这在很多场景下够用但一旦外部条件发生结构性变化比如大促、寒潮、节假日调休单靠历史值的惯性根本扛不住。ARIMAX 的数学路径可以这样理解y_t X_t β η_t其中 η_t 服从 ARIMA(p,d,q) 过程。外部变量 X_t 以普通线性回归的方式进入模型AR/MA 部分负责吸收回归后剩余误差中的时序相关性。这里有个关键点值得停下来想清楚当 d1 时模型实际拟合的是 Δy_t 对 X_t 的回归再加上对 Δy 的 AR/MA 项。也就是说外生变量通常保持原始水平值进入差分后的方程不需要像目标变量那样做差分。举个例子预测日销售额时目标序列 y 做了 1 阶差分而 x1节假日 0/1、x2最高气温、x3促销开关这些外生变量就直接按原始值放进回归式。β 的含义是X_t 每变化一个单位Δy_t 平均变化多少这跟普通线性回归里有微妙差别解读系数时不能望文生义。很多初学者栽在这个地方他们以为 ARIMAX 就是把 ARIMA 里的 y 换成多个变量结果跑去用 VAR。实际上 ARIMAX 是单方程模型外生变量是被解释侧的外部输入内生变量依然只有一个。搞清楚这个边界后面调参、看残差才不至于跑偏。2.2 为什么不用VAR、SARIMAX和Prophet选型对比表ARIMAX 在多变量预测领域并不是唯一选择甚至不算最高级的选择。做选型时我一般会把 VAR、SARIMAX、Prophet 拉出来一起比因为它们的易混程度很高用错了就是整个项目返工。模型适用场景主要限制外生变量处理方式ARIMAX单目标序列 少量已知外生变量不能捕捉复杂非线性关系以线性回归项直接接入VAR多变量互相影响且都要预测参数数量随变量数暴增样本需求量极大所有变量都是内生变量SARIMAX目标有明确日/周/月周期季节阶数设置敏感调参难度大增与 ARIMAX 相同Prophet强节假日效应、趋势突变点明显外生变量支持较弱滞后的灵活度低只支持线性自定义回归器VAR 的问题在于它对多变量的理解和 ARIMAX 完全不同。VAR 假设每个变量都被其他变量影响建模时要把所有变量的滞后项全部铺开变量一多参数立刻爆炸。如果你只想预测一个目标序列其他变量只是辅助信息那 VAR 就是在浪费自由度。SARIMAX 是 ARIMAX 的季节扩展当数据有明显的周内模式或年度模式时加一组(P,D,Q,s) 的效果立竿见影。代价是参数搜索空间变大样本不足时很容易过拟合。Prophet 在处理节假日和趋势转折时确实省心但如果你需要在预测期对某个外生变量做假设推演Prophet 的灵活度远不如 ARIMAX——它的自定义回归器不支持滞后结构。所以我的判断标准很简单只有一个目标序列、外生变量在预测期已知或可预报、周期性不显著或可以用哑变量消化就直接用 ARIMAX少给自己加戏。2.3 外生变量能用的三个硬性前提在动手写代码之前先要确认你的外生变量配得上这个模型。ARIMAX 对 X 的要求比普通回归更苛刻因为它要把 X 延伸到预测期去这决定了整个方案的可行性。第一外生变量在预测期必须是已知的或可高精度预报的。节假日日历是提前确定的天气预报能看未来几天促销排期是业务自己定的。但如果你计划用政策补贴金额竞品活动力度这种变量就得先想清楚预测期这些值从哪来否则模型训练完却没东西可推算等于白做。这一点决定了外生变量能不能最终用于滚动预测。第二外生变量与目标序列的因果方向要一致且稳定。ARIMAX 估计的 β 是样本期的平均效应如果预测期里这个关系发生反转或消失模型的预测误差会比不用它更难看。一个典型场景是促销折扣样本期里折扣拉动销量但如果预测期里折扣频繁出现、消费者已形成价格锚定效应就会衰减。遇到这种情况宁可砍掉这个变量也要保住模型的干净度。第三外生变量的滞后效应需要你手动构造。ARIMA 结构只负责处理目标序列自身的滞后X 的滞后不会自动进入模型。温度对饮品销量的影响可能滞后一天补贴对订单量的拉动可能要一周才体现这些滞后项需要你在特征工程阶段显式制造出来模型本身没有这个能力这也是 ARIMAX 和深度学习模型在特征自动提取上的核心差异。3. 源码结构与最小复现从python环境到ARIMAX训练预测全流程3.1 解压zip之后先看什么目录结构与依赖清单拿到这个 zip解压后的目录组织一般是常见的工程样式数据文件和代码文件分开代码再按职责拆成数据加载、训练、预测几个脚本外加一个 requirements.txt 和一个 README。你应该先读 README 和 requirements.txt而不是急着跑训练脚本——源码能不能跑起来九成取决于依赖版本是否匹配。在 Python 环境准备上我建议直接用虚拟环境不要往全局站点里装。这里有个来自 python 安装教程的血泪经验装完 Python 后命令行输入 python 没反应或者 pip 找不到基本都是 PATH 没配好连累后续所有依赖安装。下面是环境准备的标准操作python -m venv .venv source .venv/bin/activate # Windows 下用 .venv\Scripts\activate pip install --upgrade pip pip install -r requirements.txtrequirements.txt 里至少会包含 statsmodels、pandas、numpy、matplotlib 这几个核心库。需要特别盯住的是 statsmodels 的版本这个库的 API 变化比较折腾我一般会把它锁在 0.13,0.15 这个区间既能使用较新的 ARIMA 类又避开最新版可能引入的破坏性变更。建议在虚拟环境里跑通后再动源码因为这种解压包最怕的就是能跑但不知道跑在哪套环境上。先把 run 脚本跑出来一个结果再改参数你的可控感会强很多。3.2 数据加载与频率规范化asfreq这步不能省多数这种项目的数据集都长得很规矩第一列是日期后续列是目标序列和外生变量。但看起来规矩和statsmodels 认账之间还差一步就是频率标注。ARIMA 类模型要求 endog 和 exog 要么没有索引要么带明确频率的索引如果你只是 set_index(date) 而不声明频率训练阶段经常报Unable to infer frequency或者预测时索引对不上。代码里显式声明频率是最省心的解药import pandas as pd # 解析日期并设为索引asfreq(D) 强制声明为日频 df pd.read_csv(data/train.csv, parse_dates[date]) df df.set_index(date).asfreq(D) # 目标序列和外生变量统一转数值脏值先转 NaN df[target] pd.to_numeric(df[target], errorscoerce) df[x1] pd.to_numeric(df[x1], errorscoerce) # 节假日标记 0/1 df[x2] pd.to_numeric(df[x2], errorscoerce) # 最高气温 df[x3] pd.to_numeric(df[x3], errorscoerce) # 促销开关 0/1 # 看一眼缺失值分布后面按列处理 print(df.isna().sum()) print(df.dtypes)这段代码的逻辑是先把时间列解析成标准格式再用 asfreq(D) 把索引强制标记为日频。asfreq 的实际效果是如果原始数据中间缺了某些日期它会把缺失日期补进来target 和 x 对应位置填 NaN。这样做的代价是引入了额外缺失值收益是模型能稳定推断频率。参数说明里重点看两处parse_dates 负责把字符串日期转成 Timestamp避免之后手动 to_datetime 出意外asfreq(D) 的频率码 D 是日频如果你的数据是小时级就用 H是工作日数据可以试 B但 B 会忽略周末必须确认你的业务语义真的没有周末。缺失值在下文会专门讲策略这里只需确认有缺、知道缺在哪。3.3 训练ARIMAX的最小命令order参数怎么定数据加载干净后训练一个 ARIMAX 模型在 statsmodels 里其实就两三行。需要注意statsmodels 里没有一个叫 ARIMAX 的类ARIMAX 是通过 ARIMA 类传入 exog 参数实现的源码里大概率也是这么组织的。这里给出最简可跑版本import statsmodels.api as sm # order 先按 (2,1,2) 起步d1 表示 1 阶差分p/q 等 ACF/PACF 初步判断 model sm.tsa.ARIMA( df[target], exogdf[[x1, x2, x3]], order(2, 1, 2), ) result model.fit(methodinnovations_mle, maxiter200) print(result.summary())fit 方法里 methodinnovations_mle 是我比较推荐的参数它用状态空间表示做极大似然估计收敛速度比旧的 css-mle 快对中等长度序列很友好。maxiter200 是防止复杂模型在默认 50 次迭代内没收敛就静默退出训练时留意 summary 里有没有Maximum number of iterations reached字样有就把 maxiter 再调大。order 的 (2,1,2) 不是拍脑袋来的先用 adf 检验确定 d 需要几阶差分才能让序列平稳再对差分后的序列画 ACF/PACF 图粗看截尾和拖尾模式。一般项目到这个深度就够了更细的 p、q 挑选放到 grid search 阶段用 AIC 兜底。执行这段代码时如果报错说 exog 不是二维的回到 3.2 节检查 df[[x1, x2, x3]] 这种 DataFrame 写法别手滑写成 df[x1] 这种 Series。3.4 预测与差分还原用get_forecast避免自己算错训练完成后下一步是做预测。这里我强烈建议用 get_forecast 而不是 forecast因为前者直接给你带置信区间的对象后者只返回点预测数组一旦后期要画区间图就得返工。多步预测时 exog 的行数必须等于 steps这是源码里最容易写错的地方。import pandas as pd # 假设预测未来 3 天外生变量提前给定x1 假日、x2 气温、x3 促销 future_exog pd.DataFrame({ x1: [0, 1, 0], x2: [24.5, 27.2, 26.8], x3: [0, 1, 0], }) future_exog.index pd.date_range(start2024-06-01, periods3, freqD) # get_forecast 返回完整预测对象predicted_mean 是点预测序列 forecast_result result.get_forecast(steps3, exogfuture_exog) pred forecast_result.predicted_mean conf forecast_result.conf_int(alpha0.05) print(pred) print(conf)这段代码的逻辑是先手动构造预测期的外生变量 DataFrame再把它的索引设成未来日期。注意 get_forecast 里 exog 的行数必须严格等于 steps多一行少一行都会直接抛错这是 ARIMAX 预测环节最典型的翻车点后面避坑章还会展开。因为 d1上面拿到的 pred 是差分序列的预测值需要手动还原成原始量纲。还原的公式是 y_t y_{t-1} Δy_t多步预测时要按顺序累加。把上一节最后一个训练期真实值作为基准用 cumsum 就能完成还原。如果你在源码里看到手动还原的循环代码检查它的每一步基准是否用上一步的预测值而不是真实值——用错了就是灾难性的误差累积。4. 把数据集处理好外生变量构造、对齐与切分的完整套路4.1 数据集字段怎么设计target加三个外生变量的样例ARIMAX 项目真正值钱的部分不是模型而是数据集。同一个模型外生变量设计得好坏能让最终预测误差差出一倍。这个方案里配套的数据集通常是典型的销售/客流预测格式一列日期、一列目标值、外加若干外生变量列。字段名类型示例说明datedatetime2024-05-31时间索引必须无重复且按升序targetfloat1280.5目标序列比如日销售额x1int0/1节假日标记1 表示当天是节假日x2float28.3连续型外生变量比如最高温度x3int0/1离散型外生变量比如是否促销字段设计的原则是宁少勿多。外生变量不是越多越好每多一个变量就多一份共线性风险和一份预测期取值的不确定性。如果某列在预测期没办法拿到准确值就不要把它放进特征列表否则模型训练完没法推理。另外要注意离散型外生变量和连续型外生变量在预处理上的差异节假日和促销这种 0/1 标记填充缺失时用前向填充是合理的因为不知道是不是节假日通常意味着按上一个状态延续温度这种连续变量用前向填空会留下锯齿更适合做线性插值。数据集的原始文件里一般会留出缺失让你自己处理这也正好是练手的好机会。4.2 时间索引对齐的三个坑重复、乱序、交易日混自然日ARIMAX 对 exog 和 endog 的对齐要求比大多数人想象的严格它要求两者索引完全一致差一行都不行。我在实际项目里遇到过三次不同的对齐问题症状各异根源相似。第一个坑是索引重复。原始 csv 里偶尔会有两行相同日期的数据通常是数据上报时重复追加造成的。如果不去重asfreq 后 statsmodels 会拒绝执行或者更糟它不报错但结果失真。处理办法是先看重复再决定保留哪条# 保留每天最后一条记录然后排序 df df[~df.index.duplicated(keeplast)] df df.sort_index() # 显式声明日频把缺失日期补成 NaN df df.asfreq(D) # 连续变量用线性插值离散哑变量用前向填充 df[target] df[target].interpolate(methodlinear, limit3) df[x1] df[x1].fillna(methodffill)这段代码先说去重duplicated(keeplast) 遇到同日期多行时保留最后一条这个选择是假设后写入的记录更新。排序是为了让后续 asfreq 在有序索引上工作乱序索引在 asfreq 时会警告甚至报错。第二个坑是交易日和自然日混在一起。很多销售数据是交易日记录周日没营业就没有记录如果你用 asfreq(D) 声明日频周六周日会被补成 NaN。此时 target 的缺失不能无脑 fillna——销售额为 0 和没营业是两码事。要么把频率改成 B工作日频率要么在业务上确认补零是否合理。我这个方案里默认 asfreq(D) 加线性插值是因为示例数据集本身就是自然日连续记录你用自己的数据时务必先确认业务口径。第三个坑是外生变量和 target 的 DataFrame 索引没对齐。常见做法是把所有列放在同一个 DataFrame 里再 asfreq这样天然对齐。如果你是分别加载 target 和 exog 再合并记得用 df.merge(..., ondate, howouter) 后检查是否有 NaN别在 fit 时等报错。4.3 构造滞后外生变量温度影响销售一般慢一天外生变量直接影响当期的情况存在但更多的时候是滞后影响。比如最高气温升到 35 度冰淇淋当天的销量确实会上涨但上涨最明显的时间往往是热浪持续后的第二天——消费者先意识到天热再决定囤货。这个滞后效应 ARIMA 结构管不了得自己在特征工程里造# 温度滞后 1 天 df[x2_lag1] df[x2].shift(1) # 星期几作为外生变量捕捉周周期性 df[dow] df.index.dayofweek # 新造的滞后列第一行是 NaN用前向填充或直接丢弃前 N 行 df df.iloc[1:]shift(1) 的逻辑是把昨天的值放到今天这一行这样模型拟合时看到的就是昨天的温度对今天销量的影响。注意 shift 后第一行成了 NaN如果数据量不大我建议直接丢弃前一行因为补出来的滞后值其实没有真实信息。星期几这个变量值得说一说。ARIMAX 处理周期性有两种思路一种是上 SARIMAX 的季节项另一种就是把星期哑变量直接当外生变量。后者更直观并且系数可解释比如周一系数 -0.15 就表示周一的销量平均比基准低 15%。做这类离散变量时不要用 0-6 的整数当连续值喂进去模型会误以为周日到周一的影响是线性的应该转成哑变量或至少做 one-hot。statsmodels 对 DataFrame 里的 get_dummies 列支持得很好直接拼进 exog 就行。4.4 训练集/测试集切分差分还原用cumsum切分逻辑在时序预测里与普通机器学习完全不同不能随机打乱必须按时间顺序切而且测试集必须紧跟在训练集之后中间不能有空档否则外生变量的滞后特征会在切分边界断裂。n_test 14 # 最后 14 天作为测试集 train df.iloc[:-n_test] test df.iloc[-n_test:] exog_cols [x1, x2, x3, x2_lag1, dow] model sm.tsa.ARIMA(train[target], exogtrain[exog_cols], order(2, 1, 2)).fit() # 预测时传入测试期的真实外生变量值 pred_diff model.forecast(stepsn_test, exogtest[exog_cols]) # 差分还原最后一真实值 累计差分 last_train train[target].iloc[-1] pred last_train pred_diff.cumsum()这段代码展示了两种常见写法的区别。model.forecast 返回的是差分序列的预测pred_diff.cumsum() 是做还原逻辑是每一步都在上一步预测值基础上累加差分预测所以第一步的基准是 last_train第二步的基准变成了第一步的预测值以此类推。这个还原过程非常容易踩坑。有些人为了方便在还原时用测试集的真实值做基准结果评估指标看起来好得惊人但上线后立刻崩掉——因为在线滚动预测时你根本没有未来真实值。判断一段还原代码是否正确的方法很简单把 pred 和 test[target] 画在一张图里看两条线是否在同一个量级上如果 pred 明显偏离先检查基准是不是用了真实值。5. 避坑与排查ARIMAX实战中常见的5个翻车点5.1 报错exog must be array-like多数是object列现象fit 或者 forecast 阶段直接抛 ValueError提示 exog must be array-like or pandas DataFrame英文原文里还往往带一句e.g. a pandas DataFrame。原因最常见的是 exog 里混入了 object 类型的列。pandas 读 csv 时某列如果既有数字又有空字符串会被整体推断为 object 类型而 statsmodels 底层把它当成 Python list 处理形状检查就过不去。还有一种情况是你传了 Series 而不是 DataFrame模型要求二维结构。解决在传入模型之前打印 df[exog_cols].dtypes把所有 object 列全部转换。比较稳妥的写法是逐列做 pd.to_numeric(errorscoerce)把非法字符变成 NaN 后再填充。之后再检查 df[exog_cols].shape[1] 和 df[target].shape[0] 是否匹配。我自己的做法是把这两步封装成一个 prepare_exog() 函数每次训练前调用宁可多花两行代码也不赌数据类型正确。5.2 预测值几步就飞差分还原逻辑写错了现象预测结果前 1-2 步还像样子到第 3 步之后开始一路偏离误差持续扩大甚至出现明显违背业务常识的数值。原因差分还原时基准用错了。很多人还原时习惯用真实值更新基准即每一步都用测试集的真实 y 来加差分预测这在离线评估中显得误差很小但一旦到了真实预测场景你不可能有未来真实值模型就无从压住误差。另一类原因是 d 设得太高比如 d2 时还原要连续累加两次差分步骤越多误差累积越凶。解决确认 d 的取值用 adf 检验而不是靠直觉。差分还原时严格遵循上一步预测值 这一步差分预测的链条基准只取最后一个训练集真实值。验证方法是把还原后的 pred 和测试集真实值画在同一张图上看残差是否平稳地围绕零波动如果残差呈现出越来越大的趋势优先检查还原链路而不是模型参数。5.3 外生变量系数很大但预测更差量纲和共线性现象summary 里 x2 的系数大得离谱比如 5000 多标准误也不小把这个变量加进去后 MAE 反而恶化了。原因外生变量之间的量纲差异巨大比如 x1 是 0/1 哑变量x2 是几千量级的累积值同一套回归框架下系数会被量纲拉伸。更隐蔽的是共线性两个外生变量彼此强相关模型本身无法分离出各自的效应系数符号可能不符合直觉。解决先对连续型外生变量做标准化让它和哑变量处在同一量纲水平再看系数是否落到合理范围。如果添加后模型性能反而变差用方差膨胀因子检查共线性VIF 高于 10 的变量优先剔除。这属于多变量预测的典型坑变量不是越多越好局部很漂亮的新变量可能全局拖后腿。5.4 环境一换脚本就报错statsmodels版本API差异现象同一个脚本在自己的机器上跑得好好的放到同事机器或服务器上就报 TypeError 或者unexpected keyword argument exog。原因statsmodels 在 0.12 版本才把 ARIMA 类重构并正式支持 exog 参数0.12 之前大家用的是 SARIMAX 类来模拟 ARIMAX。如果同事环境的 statsmodels 还停留在 0.11ARIMA 类根本没有 exog 参数自然报错。反过来如果你拿旧版写法 SARIMAX(order(p,d,q), seasonal_order(0,0,0,0)) 去新版跑虽然兼容但参数名和语义容易造成混乱。解决在虚拟环境中直接锁定版本逼所有人在同一版本上开发。稳妥的做法是在 requirements.txt 里写 statsmodels0.13,0.15。如果你依赖的源码包比较老旧改用 sm.tsa.SARIMAX(endog, exog, order...) 的写法兼容性最好因为它从 0.9 到 0.14 都支持 exog。这个坑属于 python 环境配置里的常见病根源是开源库 API 演进太快锁定版本是唯一的后悔药。5.5 zip解压乱码或伪加密先确认编码再读csv现象zip 解压出来csv 文件名是乱码打开内容也是乱码更奇怪的是有些压缩包在双击时提示输入密码但 README 里根本没提密码。原因这类压缩包多数是在 Windows 下用默认编码GBK压缩的文件名的字节在 macOS/Linux 下被误读成 UTF-8所以乱码。至于提示要密码大概率遇到的是 zip 伪加密压缩包的加密标记位被置位但文件本身并没有真正加密很多解压工具检测到标记位就要求输密码。解决解压时用支持编码识别的工具比如 7-Zip 或 Bandizip它们对 GBK/UTF-8 文件名处理得更成熟。如果是伪加密可以在命令行里用 7z 直接解或者修改 zip 全局加密标志位后重新打包。读取乱码 csv 时pandas 里多试几种编码最常见的是 encodinggbk 和 encodingutf-8-sig先看列名是否正常再往下走。伪加密这个东西其实不可怕关键是别被带密码的压缩包吓住。判断方法很简单用文本编辑器打开 zip 看是否能直接看到 csv 的开头内容能看懂就说明没有真正加密。真遇到加密的压缩包走正规渠道联系作者拿密码不要花精力去破。6. 进阶验证滚动窗口与残差检验帮你判断外生变量是否真有效6.1 滚动窗口有X无X各跑一遍看MAE差多少单次训练集上的结果说服力有限ARIMAX 项目上线前我最常做的验证是滚动窗口评估把数据集切成多个连续窗口每个窗口独立训练、预测下一段最后对比有外生变量和无外生变量的 MAE。这个对比决定了外生变量到底是真信号还是纸面繁荣。from sklearn.metrics import mean_absolute_error def rolling_eval(df, exog_cols, order(2,1,2), h7, windows4): err_x, err_no 0, 0 for i in range(windows): cut len(df) - (windows - i) * h train, test df.iloc[:cut], df.iloc[cut:cut h] m1 sm.tsa.ARIMA(train[target], exogtrain[exog_cols], orderorder).fit() p1 m1.get_forecast(stepsh, exogtest[exog_cols]).predicted_mean m0 sm.tsa.ARIMA(train[target], orderorder).fit() p0 m0.get_forecast(stepsh).predicted_mean err_x mean_absolute_error(test[target], p1) err_no mean_absolute_error(test[target], p0) return err_x / windows, err_no / windows mae_x, mae_no rolling_eval(df, exog_cols) print(fwith exog: {mae_x:.2f}, without: {mae_no:.2f})这段代码的核心是每次滚动只取前 cut 行训练、预测其后的 h 行测试集不重叠也不越过末尾边界。外生变量版传入 test 的真实外生值无外生变量版则完全靠 ARIMA 自身惯性。如果 mae_x 比 mae_no 低 10% 以上说明外生变量确实提供了增量信息如果差距很小甚至更差就回头检查滞后项构造或共线性问题。6.2 残差白噪声与AIC选阶用检验数字说服别人模型是否把时序信息榨干了一个严肃的检验是 Ljung-Box 残差白噪声检验。残差的 p 值大于 0.05 说明没有明显的自相关残留模型结构基本合理p 值很小说明还有信息藏在残差里应该增加 p 或 q 阶数。from statsmodels.stats.diagnostic import acorr_ljungbox resid result.resid print(acorr_ljungbox(resid, lags[10], return_dfTrue))这个检验只对训练集残差有意义所以我会在 order 调整阶段高频使用而不是在最终模型上跑一次就完事。选阶方面我在小范围内网格搜索 p,q用 AIC 取最优但不会把 p,q 上限拉得太高因为 ARIMAX 的参数越多对样本量的要求就越高过拟合的风险增长比收益快得多。我自己做这类项目养成了一个固定习惯不管模型在测试集上成绩多好上线前一定先把有 X 和无 X 两版在滚动窗口上的 MAE 都保存下来因为只有拿到这份对照才有底气象业务方解释清楚外生变量到底值不值得维护。这也算是这条路上最值得多做一步的一个验证动作希望帮到你。本文还有配套的精品资源点击获取
返回列表