ARIMA模型利用历史数据对时间序列进行预测,属于参数型方法,全称Autoregressive Integrated Moving Average Model,是集合了自回归模型AR(Autoregressive)、移动平均模型MA(Moving Average)和差分过程I(Integrated)的模型。
ARIMA(p,d,q)模型中的参数p, d, q分别来源于对应的三个部分:
AR部分:利用过去的值来预测未来的值,假设是线性关系,即利用过去p个值的加权平均来进行预测;
I差分部分:通过差分操作,来消除时间序列中的趋势和季节性因素,d代表差分的阶数;
MA部分:利用过去的误差来预测未来的值,假设时间序列是平稳的,也假设呈线性关系,利用过去q个白噪声的加权平均来进行预测。
实现ARIMA模型使用statsmodels包:statsmodels.tsa.arima.model.ARIMA。
一、基本用法
构建模型
from statsmodels.tsa.arima.model import ARIMA
model = ARIMA(data, order=(7,0,1))
model_fit = model.fit()
模型训练时输入什么类型,则预测输出也是同样的类型,输入array,预测结果也是array, 输入带datetimeindex的series或dataframe,预测结果也是带datetimeindex的series或dataframe,其中datetimeindex需要指定频率,因为ARIMA模型要求时间序列的时间间隔相等。
forecast预测
pred = model_fit.forecast() # 一步预测
pred = model_fit.forecast(steps=5) # 多步预测 指定步数
pred = model_fit.forecast('2012-03-06 14:40:00') # 多步预测 指定end datetime
ARIMA模型本质只能预测未来一步,多步预测采用的是recursive循环的计算方法。
predict预测
# 指定要预测区间的起止index,index是相对于模型训练数据而言的,训练数据的第一个ts的index为0
pred = model_fit.predict(start=start_index, end=end_index)
# 只有一个输入时,代表start index,预测start index至数据集的最后一个ts
pred = model_fit.predict(1000)
# 指定要预测区间的起止datetime
pred = model_fit.predict(start='2012-03-06 14:20:00', end='2012-03-07 23:55:00')
其中有个参数“dynamic”,dynamic=False代表使用真值true value, dynamic=True则使用预测值predicted value,例如在对 t + 1 t+1 t+1时刻预测时,使用的所有历史值都是真值,但对 t + 2 t+2 t+2时刻预测时,需要用到 t + 1 t+1 t+1时刻的值,可以使用真值,也可以使用模型的预测值。
forecast VS predict
forecast和predict的主要差别在于forecast只能对未来进行计算,而predict可以对过去进行计算,即官方说明中的,forecast是out-of-sample forecasting,predict是In-sample prediction and out-of-sample forecasting。
还有两个方法get_forecast和get_prediction,用法与之类似,只是相比forecast和predict会额外返回置信区间。
二、预测实例
数据使用los loop,数据取自数据集METR-LA,由洛杉矶高速公路上的环形探测器检测得到的车速,采样频率5min,共四个月,论文作者取了2012年3月1日-3月7日七天的数据,并对缺失数据进行了线性插值处理。
按照8:2划分训练集和测试集,验证ARIMA模型的准确性。
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimSun']
data = pd.read_csv('./data/los_speed.csv')
time_len = data.shape[0] # 2016个ts
num_nodes = data.shape[1] # 207个检测器
data.index = pd.date_range('2012-03-01', periods=2016 , freq='5min') # 设置datetimeindex
ts = data.iloc[:,10] # 只取某一个检测器
train_size = int(time_len * 0.8)
train_ts, test_ts = ts[0:train_size], ts[train_size:]
训练集train_ts如下:
2012-03-01 00:00:00 55.500000
2012-03-01 00:05:00 58.777778
2012-03-01 00:10:00 61.375000
2012-03-01 00:15:00 62.138889
2012-03-01 00:20:00 62.902778
...
2012-03-06 13:55:00 64.875000
2012-03-06 14:00:00 63.000000
2012-03-06 14:05:00 64.000000
2012-03-06 14:10:00 64.000000
2012-03-06 14:15:00 64.000000
Freq: 5T, Name: 765604, Length: 1612, dtype: float64
训练集test_ts 如下:
2012-03-06 14:20:00 64.000000
2012-03-06 14:25:00 62.250000
2012-03-06 14:30:00 63.666667
2012-03-06 14:35:00 63.250000
2012-03-06 14:40:00 60.875000
...
2012-03-07 23:35:00 67.111111
2012-03-07 23:40:00 66.125000
2012-03-07 23:45:00 61.000000
2012-03-07 23:50:00 67.000000
2012-03-07 23:55:00 64.125000
Freq: 5T, Name: 765604, Length: 404, dtype: float64
# 构建模型
model = ARIMA(train_ts,order=[12,0,1]) # 利用过去12条数据来预测未来
properModel = model.fit()
## 预测1,使用预测值预测
# 模型的样本中只有2012-03-06 14:15:00前的数据,无论dynamic取何值,预测时只能用预测值
predict1 = properModel.predict(start='2012-03-06 14:20:00', end='2012-03-07 23:55:00')
## 预测2,使用真值预测
# 为了预测时能使用真值,加上测试数据,但不重新训练模型,即模型的参数不变,只是模型的样本改变了
newModel = properModel.append(test_ts, refit=False)
predict2 = newModel.predict(start='2012-03-06 14:20:00', end='2012-03-07 23:55:00',dynamic=False)
fig, ax = plt.subplots(figsize=(15,4))
ax.plot(test_ts, label='groundtruth')
ax.plot(predict1, label='使用预测值')
ax.plot(predict2, label='使用真值')
plt.legend()
plt.show()
由图可知,预测时如果只使用预测值,因为采用循环计算策略,会导致误差不断累积;
而如果预测时使用过去的真值,即预测
t
+
2
t+2
t+2时刻的值时,使用
t
+
1
t+1
t+1时刻的真值,预测
t
+
3
t+3
t+3时刻的值时,又使用
t
+
2
t+2
t+2时刻的真值,符合实际运行情况,每一步的预测结果的准确度相对稳定,误差不会随着时间而累积。