You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于SARIMAX(MA(1)-X)模型实现样本外一步向前预测?

解决SARIMAX一步向前预测的索引匹配错误问题

问题原因

你遇到的索引错误,是因为predict方法默认会匹配训练数据的索引范围,而测试集索引不在训练数据的索引序列里,导致无法定位。另外,直接用predict传入测试集exog做的是静态预测,不是你需要的基于前一步结果的一步向前动态预测。

解决方案

方法1:使用get_prediction实现动态一步向前预测

statsmodels的get_prediction方法支持dynamic参数,设置为测试集起始索引后,会从该点开始用前一步的预测值作为输入,自动实现动态一步向前预测。

修改后的代码:

import statsmodels.api as sm
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score
import pandas as pd

# 训练测试拆分(原代码保留)
train_mask = xc.index < cutoff_date
xc_train, xc_test, yc_train, yc_test = xc[train_mask], xc[~train_mask], yc[train_mask], yc[~train_mask]

# 定义并训练MA(1)-X模型
model_ma1x = sm.tsa.SARIMAX(yc_train, exog=xc_train, order=(0, 0, 1))
results_ma1x = model_ma1x.fit()

# 用get_prediction做动态一步向前预测
pred_results = results_ma1x.get_prediction(
    start=yc_test.index[0], 
    end=yc_test.index[-1],
    exog=xc_test,
    dynamic=yc_test.index[0]
)
pred_ma1x = pred_results.predicted_mean

# 绘图和评估(修正原代码中R2计算的错误,改用测试集数据)
yc_test.plot(label='Actual', legend=True)
pred_ma1x.plot(label='Predicted', legend=True)
plt.title('MA(1)-X Model (Dynamic One-Step Ahead)')
plt.annotate(f'R2: {r2_score(yc_test, pred_ma1x):.3f}', xy=(0.95, 0.05), xycoords='axes fraction', 
            ha='right', va='bottom', fontsize=9)
plt.show()

print(results_ma1x.summary())

方法2:手动循环实现一步向前预测(完全贴合需求)

如果需要严格基于前一步预测值+新实际外生变量做逐步预测,可以手动循环测试集,每次用真实值更新模型状态(保持训练好的MA系数不变):

import statsmodels.api as sm
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score
import pandas as pd

# 训练模型(原代码保留)
train_mask = xc.index < cutoff_date
xc_train, xc_test, yc_train, yc_test = xc[train_mask], xc[~train_mask], yc[train_mask], yc[~train_mask]

model_ma1x = sm.tsa.SARIMAX(yc_train, exog=xc_train, order=(0, 0, 1))
results_ma1x = model_ma1x.fit()

# 初始化预测列表和当前模型状态
preds = []
current_results = results_ma1x

# 逐步遍历测试集
for idx, exog_val in xc_test.iterrows():
    # 执行一步向前预测
    pred = current_results.predict(start=idx, end=idx, exog=[exog_val.values])[0]
    preds.append(pred)
    
    # 用真实值更新模型历史,保持训练好的参数不变
    updated_endog = current_results.model.endog.append(yc_test.loc[idx:idx])
    updated_exog = current_results.model.exog.append(exog_val.to_frame().T)
    
    # 基于更新后的历史创建新模型,加载已训练参数
    updated_model = sm.tsa.SARIMAX(updated_endog, exog=updated_exog, order=(0, 0, 1))
    current_results = updated_model.filter(results_ma1x.params)

# 转换为Series方便绘图
pred_ma1x = pd.Series(preds, index=yc_test.index)

# 绘图和评估
yc_test.plot(label='Actual', legend=True)
pred_ma1x.plot(label='Predicted', legend=True)
plt.title('MA(1)-X Model (Manual One-Step Ahead)')
plt.annotate(f'R2: {r2_score(yc_test, pred_ma1x):.3f}', xy=(0.95, 0.05), xycoords='axes fraction', 
            ha='right', va='bottom', fontsize=9)
plt.show()

print(results_ma1x.summary())

关键说明

  • 方法1的dynamic参数会自动处理状态更新,代码简洁,适合快速实现动态预测。
  • 方法2的手动循环更灵活,严格按照你“基于前一步预测和新实际数据”的要求,每次用真实值更新模型历史,确保每一步预测都依赖上一步的结果。
  • 原代码中的R2计算存在逻辑错误,已经修正为用测试集实际值和预测值对比。

内容的提问来源于stack exchange,提问作者user20487324

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:23:23