目录

前言

在对时间序列进行ARIMA(p,d,q)建模的时候,一个比较头疼的事就是确定其中超参数p, d, q, 常规做法是先用平稳性检验来确定d,然后通过ACF图和PACF图来观察p和q,这种通过机器和人工肉眼识别相结合的方法一套走下来往往还容易出错,如果只对一个时间序列进行分析还好,如果要对很多个时间序列进行批量建模的话,时间成本就太高了,然而,现在越来越多的朋友在进行时间序列分析的时候直接调用auto_arima也能够取得较好的效果,而且能够节省很多时间,总的来看auto_arima有几大好处

(1) 自动寻参

(2) 自动拟合

(3) 自动预测

auto_arima参数列表

下图是pmdarima 1.8.5版本的auto_arima函数参数的提示,由于参数太多了,我们先进行梳理

时间序列分析|auto_arima调参_时间序列分析

参数

含义

备注

y

要拟合的时间序列

必要,array-like or iterable, shape=(n_samples,),⼀维的浮点型数组,不能包含空值和或者无穷’

X

外置变量

非必要,给定额外的特征来帮助预测,需要注意的是,对于预测未来的时序数据的时候,也要提供未来的特征数据

start_p

参数p的下界

int, 默认为2

d

⾮周期的差分阶数

int, 默认None,如果是None,则⾃动选择,此时,运⾏时间会显著增加。

start_q

参数q时的下界

int, 默认为2

max_p

参数p的上界

int, 默认为5,max_p>=start_p

max_d

⾮周期的差分阶数d的上界

int, 默认2,max_d>=d

max_q

参数q时的上界

int, 默认5,max_q>=start_q

start_P

周期参数P的下界

int,默认1

D

周期差分的阶数

int,默认None,如果是None,则⾃动选择

start_Q

周期参数Q的下界

int, 默认1

max_P

周期参数P的上界

int,默认2

max_D

周期的差分阶数的上界

int, 默认1, max_D>=D

max_Q

周期参数Q的上界

int,默认2

max_order

p+q+P+Q 组合最大值

int, 默认5,如果p+q≥max_order,该组合对应的模型将不会被拟合,如果是None的话,对最大阶没有限制

m

周期数

int, 默认1,例如年数据 m=1,季度数据m=4,月度数据m=12,周数据52;如果m=1, 则seasonal会被设置为False

seasonal

是否进⾏周期性ARIMA拟合

bool, 默认True,如果seasonal=True同时m=1,seasonal会被设置为False

stationary

标志该序列是否是平稳序列

bool, 默认False

information_criterion

模型评价指标

str, 默认’aic’,可选‘aic’, ‘bic’, ‘hqic’,'oob’

alpha

test的显著性⽔平

float,默认0.05

test

单位根检验的类型

str, 默认’kpss’,当非平稳且d=None才会进⾏检验, 当出现奇异值分解错误可选adf

seasonal_test

周期单位根检验⽅法的标志

str, 默认‘ocsb’,可选’ch’

stepwise

是否采用stepwise 算法

bool, 默认True,可以更快速的找到最佳模型和防止过拟合,但存在不是最佳模型的风险,这样课可以设置成False,模型搜寻范围扩大,耗时也会增加

n_jobs

并行拟合模型的数目

int,默认1,如果为-1,则尽可能多的并行,提速用

start_params

ARMA(p,q)的起始参数

array-like, 默认None

trend

多项式趋势的多项式的系数

str or iterable,‘n’, ‘c’, ‘t’ , ‘ct’ 选择 ,其中n表示没有,c表示常数,t:线性,ct:常数+线性

method

似然函数的类型

str, 默认lbfgs, 可选{‘css-mle’,‘mle’,‘css’}之⼀

maxiter

求解最大迭代次数

int, 默认50

transparams

是否检验平稳性和可逆性

bool,默认True,如果为True,则进⾏变换确保平稳性,如果为False,不检验平稳性和可逆性

suppress_warnings

是否过滤掉警告

bool, 默认True

error_action

是否跟踪错误提示

str, 默认 ‘trace’,如果由于某种原因无法匹配ARIMA,则可以控制错误处理行为。(warn,raise,ignore,trace)

trace

是否跟踪拟合过程

bool, 默认False

random

是否随机搜索,而不是超参数空间全搜索或者stepwise搜索,

bool, 默认False

with_intercept

是否需要截距 ,均值漂移

str, 默认auto

disp

收敛信息的打印控制

int, 默认0,disp<0表⽰不打印任何信息

实践案例

我们以air_passenger数据集为对象进行auto_arima调参,先来看一下原数据长什么样子并对其进行可视化

import datetime
import time
import tsod
import pandas as pd
import pmdarima as pm
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from sklearn.metrics import mean_absolute_error

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

air_passenger.set_index("month", inplace = True) #设置time列为索引列
ts = air_passenger['passenger'] #乘客时序
print(ts.head(5)) #查看头5行
print(ts.tail(5)) #查看尾5行

fig = plt.figure(figsize = (6,4)) #新建6*4的画布
ts.plot(label = 'origin ts') #原时序图
plt.xticks(rotation =45) #横坐标逆时针倾斜45度
plt.legend()
plt.show()

n_periods = 5 #取n_periods为测试集
train_ts = ts[0:-n_periods] #训练数据
test_ts = ts[-n_periods:] #测试数据
print(train_ts)
print(test_ts)

输出的内容

month
1949-01-01 112
1949-02-01 118
1949-03-01 132
1949-04-01 129
1949-05-01 121
Name: passenger, dtype: int64
month
1960-08-01 606
1960-09-01 508
1960-10-01 461
1960-11-01 390
1960-12-01 432

时间序列分析|auto_arima调参_数据_02

month
1949-01-01 112
1949-02-01 118
1949-03-01 132
1949-04-01 129
1949-05-01 121
...
1960-03-01 419
1960-04-01 461
1960-05-01 472
1960-06-01 535
1960-07-01 622
Name: passenger, Length: 139, dtype: int64
month
1960-08-01 606
1960-09-01 508
1960-10-01 461
1960-11-01 390
1960-12-01 432
Name: passenger, dtype:

把数据划分为训练集和测试集,就可以拿训练集来训练,拿测试集来评估训练的好坏,接下来我们来结合auto_arima的超参数进行一些不同的建模试尝试

  • 首先是不带任何超参的模型,只有要拟合的时序train_ts,此时所有的超参都是默认设置。
start_time = time.time() #开始时间
model = pm.auto_arima(train_ts,
) #模型初始化,什么都默认
print("best model:", model) #拟合出来最佳模型
y_pred = model.predict(n_periods) #预测未来n_periods期
mae = mean_absolute_error(test_ts.values, y_pred)
print("mean_absolute_error: ", mae)
end_time = time.time() #结束时间
print("cost time: ", end_time - start_time) #耗时

对应的输出结果

best model:  ARIMA(4,1,3)(0,0,0)[0]          
mean_absolute_error: 53.99503219911581
cost time: 6.462592124938965

从输出的结果我们看到拟合最好的模型是 ARIMA(4,1,3)(0,0,0)[0],在测试集上算的平均绝对误差是 53.99503219911581,耗时为14.3秒, 我们把这个作为一个baseline基准,进行各超参的增删改查。

  • stepwise算法

原auto_arima默认是stepwies = True,我们加入一个stepwies = False的超参数看一看效果

start_time = time.time() #开始时间
model = pm.auto_arima(train_ts,
stepwise=False
) #模型初始化
print("best model:", model) #拟合出来最佳模型
y_pred = model.predict(n_periods) #预测未来n_periods期
mae = mean_absolute_error(test_ts.values, y_pred)
print("mean_absolute_error: ", mae)
end_time = time.time() #结束时间
print("cost time: ", end_time - start_time) #耗时

输出结果

best model:  ARIMA(0,1,4)(0,0,0)[1] intercept
mean_absolute_error: 76.7801771043133
cost time: 5.194381237030029

在设置stepwise=False之后,最佳拟合的ARIMA变了有了季节因子的SARIMA,耗时更少,平均绝对误差变大了,这与我们预想的好像不太一样。

  • season

从原时序图可以很明显的观察到该时序是周期性的,那么我们就往里面加入season参数

start_time = time.time() #开始时间
model = pm.auto_arima(train_ts,
seasonal = True,
seasonal_test= 'ocsb',
) #模型初始化
print("best model:", model) #拟合出来最佳模型
y_pred = model.predict(n_periods) #预测未来n_periods期
mae = mean_absolute_error(test_ts.values, y_pred)
print("mean_absolute_error: ", mae)
end_time = time.time() #结束时间
print("cost time: ", end_time - start_time) #耗时

输出结果

best model:  ARIMA(4,1,3)(0,0,0)[0]          
mean_absolute_error: 53.99503219911581
cost time: 6.30750584602356

从输出结果来看,虽然设置了season = True和seasonal_test= ‘ocsb’,但是拟合的最佳模型季节阶还是0,明显没寻出季节性参数,难道auto_arima对季节性时序失效?

  • trend

从原时序图我们还看到了乘客人数有整体上升的趋势,于是可以加入trend超参

start_time = time.time() #开始时间
model = pm.auto_arima(train_ts,
trend = 'c',
) #模型初始化
print("best model:", model) #拟合出来最佳模型
y_pred = model.predict(n_periods) #预测未来n_periods期
mae = mean_absolute_error(test_ts.values, y_pred)
print("mean_absolute_error: ", mae)
end_time = time.time() #结束时间
print("cost time: ", end_time - start_time) #耗时

输出结果

best model:  ARIMA(1,1,1)(0,0,0)[0]          
mean_absolute_error: 156.21293010494168
cost time: 3.42095947265625

从输出结果来看,在测试集上面的表现似乎越来越糟糕了,是不是trend要结合season一起用呢?

  • season+trend
start_time = time.time() #开始时间
model = pm.auto_arima(train_ts,
seasonal = True,
seasonal_test = 'ocsb',
trend ='c',
) #模型初始化
print("best model:", model) #拟合出来最佳模型
y_pred = model.predict(n_periods) #预测未来n_periods期
mae = mean_absolute_error(test_ts.values, y_pred)
print("mean_absolute_error: ", mae)
end_time = time.time() #结束时间
print("cost time: ", end_time - start_time) #耗时

输出结果

best model:  ARIMA(1,1,1)(0,0,0)[0] intercept
mean_absolute_error: 156.21293010494168
cost time: 3.403970718383789

这与只留trend没有本质区别嘛,季节因子还是没寻得,是不是要预设的一个季节因子呢?

  • m

由前面的试验猜测可能季节因子m需要预先设定,不如加入m=12试一试

start_time = time.time() #开始时间
model = pm.auto_arima(train_ts,
m =12,
seasonal = True,
seasonal_test= 'ocsb',
trend = 'c',
) #模型初始化
print("best model:", model) #拟合出来最佳模型
y_pred = model.predict(n_periods) #预测未来n_periods期
mae = mean_absolute_error(test_ts.values, y_pred)
print("mean_absolute_error: ", mae)
end_time = time.time() #结束时间
print("cost time: ", end_time - start_time) #耗时

输出结果

best model:  ARIMA(1,1,0)(0,1,0)[12] intercept
mean_absolute_error: 32.80372154610323
cost time: 6.767233610153198

从输出结果来看,似乎表现得比之前好一些,时间更少了,测试集上得绝对误差也更低了。

  • all in one

从上面的几个试验可以看到auto_arima有其一定的优势,但是也有一些鸡肋的地方,尤其是在季节性表现上很糟糕,现在我们尽可能多加入一些超参试一试

start_time = time.time() #开始时间
model = pm.auto_arima(train_ts,
start_p = 1, d= None, start_q = 1,
max_p = 5, max_d = 2, max_q = 5,
start_P = 1, D = None, start_Q = 1,
max_P = 2, max_D = 1, max_Q= 2,
max_order = None,
test = 'kpss',
m =12,
seasonal = True,
seasonal_test= 'ocsb',
trend = 'c',
information_criterion ='aic',
trace = False,
with_intercept = 'auto',
error_action = 'ignore',
suppress_warnings = True,
maxiter= 100,
stepwise=False
) #模型初始化
print("best model:", model) #拟合出来最佳模型
y_pred = model.predict(n_periods) #预测未来n_periods期
mae = mean_absolute_error(test_ts.values, y_pred)
print("mean_absolute_error: ", mae)
end_time = time.time() #结束时间
print("cost time: ", end_time - start_time) #耗时

输出效果

best model:  ARIMA(0,1,1)(1,1,2)[12]          
mean_absolute_error: 20.186490167443377
cost time: 907.6581890583038

从输出效果来看,测试集上的绝对误差明显降低,但是耗时也显著提高。

结论

不要轻易的认为auto_arima就是一种一劳永逸的省时省力的好方法,然后一招打遍天下无敌手,如果分析的时序不多的话还是按照经典时序分析步骤一步一步的来为好,在仔细权衡时效性和精准性两方面再决定用不用auto_arima。

参考文献

1,https://wenku.baidu.com/view/e393289efe0a79563c1ec5da50e2524de518d027.html

2,https://stats.stackexchange.com/questions/120806/frequency-value-for-seconds-minutes-intervals-data-in-r

3,http://alkaline-ml.com/pmdarima/modules/generated/pmdarima.arima.auto_arima.html?highlight=auto_arima