目录

  • ​​前言​​
  • ​​数据预处理​​
  • ​​auto_arima多步预测​​
  • ​​auto_arima逐步预测​​
  • ​​结果对比​​
  • ​​SARIMAX多步预测​​
  • ​​SARIMAX逐步预测​​
  • ​​结论​​
  • ​​参考文献​​

前言

在做时间序列预测的时候,很多场景不只是要预测下一期的结果,称为单期预测,更多的场景是要预测未来好几期的结果,称为多期预测,与单期预测不同,多步预测对输入资料要求更高,更能看出模型的稳健性。针对多期预测,可以一次性多步预测,也可以逐步预测,这一期,我们就来看一下auto_arima下两者的区别,为此我们先做一些预处理工作。

数据预处理

import datetime
import time
import pandas as pd
import pmdarima as pm
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from sklearn.metrics import mean_absolute_error
from tsod import RangeDetector,GradientDetector,ConstantGradientDetector,RollingStandardDeviationDetector,DiffDetector

air_passenger = pd.read_csv(r"D:\项目\时间序列\air_passenger.csv") #读取数据
air_passenger['date'] = pd.to_datetime(air_passenger['date']) #datetime格式化

air_passenger = air_passenger[["date", "passenger"]].sort_values(by="date") #按日期升序排序
air_passenger.set_index("date", inplace = True) #重置索引, 将date_设置为索引index
ts = air_passenger["passenger"] #乘客人数序列
# print("原序列\n", ts)
ts_rolling = ts.rolling(window = 7).mean() #7阶截尾滑动平均
ts_rolling_std = ts_rolling.std() #标准差
# print("滑动平均:\n", ts_rolling, ts_rolling_std)
upper = (lambda x, y: x>y+1.5*ts_rolling_std)(ts, ts_rolling)
lower = (lambda x, y: x<y-1.5*ts_rolling_std)(ts, ts_rolling)
# print(upper, lower)
ts_filter = ts.drop(labels = ts[upper].index) #去上异常值
ts_filtered = ts_filter.drop(labels = ts[lower].index)#去下异常值
# print("过滤后序列\n", ts_filtered)
plt.plot(ts, color = 'red', alpha = 1.0, label = 'ts_origin') #原序列
plt.plot(ts_rolling, color = 'blue', alpha = 0.8, label = 'ts_rolling',) #移动平均序列
plt.plot(ts_filtered, color = 'green', alpha = 0.5,label = 'ts_filtered') #过滤后序列
plt.fill_between(ts_rolling.index, ts_rolling-2*ts_rolling_std, ts_rolling+2*ts_rolling_std, color='yellow', alpha= 0.2)
plt.xticks(rotation =45) #横坐标逆时针倾斜45度
plt.legend()
plt.show()
data_train, data_test = ts_filtered[0:-7],ts_filtered[-7:] #训练集和测试集划分

时间序列分析|逐步预测与多步预测_数据预处理


经过数据预处理后,我们将一些特别异常的数据进行了识别与去除,划分出训练集和测试集,把最后的7期预留出作为测试集来计算平均绝对误差以评估模型的好坏和对比两种预测方法的区别

auto_arima多步预测

多步预测就是指在一个预测动作里面一次性把未来好几期的预测结果给出来

model = pm.auto_arima(data_train,
trace = False,
error_action = 'ignore',
suppress_warnings = True,
stepwise = True) #模型初始化
print("optimum model:", model)
y_pred = model.predict(len(data_test)) #预测未来n_periods期
print(y_pred.tolist()) #7期的预测值

mape = mean_absolute_error(y_pred, data_test.ravel())
print("平均绝对误差{}".format(mape))

输出如下结果

optimum model:  ARIMA(1,0,1)(0,0,0)[0] intercept
[146.60965843758422, 148.6120385502188, 150.47826751916435, 152.21760289437896, 153.83867276191097, 155.34951854407993, 156.75763488947405]
平均绝对误差18.218789344151855

auto_arima逐步预测

与多步预测不同,逐步预测是指每次只预测(当前的)未来一期,再将预测出来的值添加进原来训练的集合作为新的训练集,再预测下一期,如此往复,直到预测到预设的期数为止。

history = [i for i in data_train] #用来存放历史训练数据
predictions = [] #用来存放预测值
for x in range(len(data_test)):
model = pm.auto_arima(history,
trace = False,
error_action = 'ignore',
suppress_warnings = True,
stepwise = True)
yhat = model.predict(1)
history.append(yhat[0]) #把预测出来的值追加进训练数据集作为下一期的输入
predictions.append(yhat[0])

print(predictions) #每期的预测值累计
mape = mean_absolute_error(predictions, data_test.ravel())
print("平均绝对误差{}".format(mape))

输出的结果如下

[146.60965843758422, 148.611882989061, 150.477618392079, 152.2162339139722, 153.83679376475382, 155.34602497830014, 156.75262325676604]
平均绝对误差18.217923357127994

结果对比

对比多步预测和逐步预测两者输出的7个预测值,似乎没有很大的区别,第一个都是146.60965843758422,从第二个预测值开始才有细微的差异,在利用auto_arima预测没有区别,似乎可以推断auto_arima的多步预测本质上就是按照逐步预测进行的,再来看一下statsmodels下面的SARIMAX是不是多步预测与逐步预测一致呢?

SARIMAX多步预测

有了前面的对比,这里我们就直接上代码了

## SARIMAX多步预测
from statsmodels.tsa.statespace.sarimax import SARIMAX

model = SARIMAX(data_train,
trace = False,
error_action = 'ignore',
suppress_warnings = True,
stepwise = True).fit(disp=False) #模型初始化

y_pred = model.forecast(7) #预测未来n_periods期
print(y_pred.tolist()) #7期的预测值

mape = mean_absolute_error(y_pred, data_test.ravel())
print("平均绝对误差{}".format(mape))

输出结果如下

[122.33773419447333, 120.69775167610975, 119.07975372921341, 117.48344564248269, 115.90853665532987, 114.35473990492028, 112.82177237392153]
平均绝对误差32.815967025109806

SARIMAX逐步预测

## SARIMAX逐步预测
from statsmodels.tsa.statespace.sarimax import SARIMAX

history = [i for i in data_train] #用来存放历史训练数据
predictions = [] #用来存放预测值
for x in range(len(data_test)):
model = SARIMAX(history,
trace = False,
error_action = 'ignore',
suppress_warnings = True,
stepwise = True).fit(disp=False)
yhat = model.forecast(1)
history.append(yhat[0]) #把预测出来的值追加进训练数据集作为下一期的输入
predictions.append(yhat[0])

print(predictions) #每期的预测值累计
mape = mean_absolute_error(predictions, data_test.ravel())
print("平均绝对误差{}".format(mape))

输出结果如下

[122.33773419447333, 120.69839400593617, 119.0816513593588, 117.48718308350502, 115.91467084198949, 114.3638010234219, 112.83426483718424]
平均绝对误差32.81129838085763

结论

可以看到SARIMAX的预测结果与auto_arima的预测结果截然不同,表现出2种不同的调性,SARIMAX多步预测与逐步预测也未表现出明显的差异性, 这点与auto_arima类似,似乎可以得出结论,auto_arima与SARIMAX两者在多步预测与逐步预测2种预测方式上表现几乎一致,如果以后你在做多期预测的时候,也许没必要画蛇添足逐步来完成。

参考文献

1,https://pypi.org/project/pmdarima/
2,https://www.statsmodels.org/stable/tsa.html