还是先来吐槽
时间序列模型arima 用python 实现的话是用statsmodels.tsa.arima_model 来做,样本内的拟合和预测都没什么问题。但是样本外的预测没想到 竟然成了很大的问题。
问题
- 无论是forecast 还是predict 在预测的时候都只能做到一步预测,如果进行多步预测,其实在后面几步用的是拟合值而不是真实值,所以对于想要使用滑窗一步预测就很难受。
- 为什么这个接口对于这么简单的功能却这么蹩脚,主要是因为在arima model 进行预测的时候是必须依赖该数据之前的数的残差。
解决问题
所以就第一个直观的想法就是
能不能取出之前模型估计的参数,然后根据喂进去新的数据,再进行计算
查了很多资料,终于在这个的基础上使用_arma_predict_out_of_sample这个内置函数,进行了改进,才得以搞定。不过一定要注意的是,这个只能进行样本外的一步预测。
实践部分
生成数据
import pandas as pd
import numpy as np
from statsmodels.tsa.arima_model import ARMA #模型
from statsmodels.tsa.arima_model import _arma_predict_out_of_sample
## 生成随机数
data=np.random.rand(200)
df= pd.DataFrame({'data':data})
分割train_dataset 和test_dataset
length = len(df)
train_data = df.iloc[0:int(length/8)*7,:]
test_data = df.iloc[int(length/8)*7:,:]
生成模型
result = ARMA(train_data['data'],order=(2,1)).fit()
pred = result.predict()
最关键的部分 ,提取参数
params = result.params
residuals = result.resid
p = result.k_ar
q = result.k_ma
k_exog = result.k_exog
k_trend = result.k_trend
steps = 1
样本内数据验证
## 样本内测试
in_data = train_data.iloc[0:11,:]
in_resid = residuals.iloc[0:11]
a = _arma_predict_out_of_sample(params, steps, in_resid, \
p, q, k_trend, k_exog,\
endog = in_data['data'], exog=None, start=len(in_data))
test_pred=pred[8:13]
test_pred
a[0]## 会发现没什么误差
样本外预测,滑窗式操作
new_resid = residuals.tail(3).copy()
new_data = train_data.tail(3).copy()
for i in range(len(test_data)):
print(i)
## temp_data 应该增加最后一行,减去第一行
a = _arma_predict_out_of_sample(params, steps, new_resid, \
p, q, k_trend, k_exog,\
endog = new_data['data'], exog=None, start=len(new_data))
tomorrow_index = test_data.index[i]
temp_resid = test_data.loc[tomorrow_index,'data'] - a[0]
new_resid[tomorrow_index] = temp_resid
new_resid.drop(new_resid.index[0],inplace=True)
new_data = new_data.append(test_data.iloc[i,:])
new_data.drop(new_data.index[0],inplace=True)
pred[tomorrow_index] = a[0]
_arma_predict_out_of_sample具体参数解读
- start 参数
未完待续......