我们都知道用于时序分析和预测的ARIMA模型可能很难配置。
需要通过反复地审查诊断图和已经使用了40多年的启发式策略中训练并修正三个参数的错误。
我们可以通过使用网格搜索过程来自动化评估ARIMA模型的大量超参数的过程。
在本教程中,您将了解如何使用Python中的超参数网格搜索来调整ARIMA模型。
完成本教程后,您将知道:
让我们开始吧。
时间序列的诊断图可以与启发式策略一起使用以确定ARIMA模型的超参数。
他们可以大多数都可以确定ARIMA模型的参数,但有的时候不能确定。
我们可以使用不同的模型超参数的组合来自动化训练和评估ARIMA模型。在机器学习中,这被称为网格搜索或模型调整。
在本教程中,我们将开发一种网格搜索ARIMA超参数的单步滚动预测方法。
该方法分为两部分:
本教程中的代码使用Python库是scikit-learn,Pandas和statsmodels。
我们可以通过在训练数据集上准备ARIMA模型并评估测试数据集的预测来评估ARIMA模型。
这种方法涉及以下步骤:
我们可以在Python中将其实现为一个新的独立函数,名为evaluate_arima_model(),它将时间序列数据集作为输入,以及具有p,d和q参数的元组作为输入。
数据集分为两部分:初始训练数据集为66%,测试数据集为剩余的34%。
我们需要对测试集的数据进行迭代。只需要一次迭代就可以提供一个可以用来对新数据进行预测的模型。迭代方法允许每个时间步骤训练新的ARIMA模型。
每次迭代都进行一次预测并存储在一个列表中。这样,在测试集结束时,所有预测都可以与期望值列表进行比较,并计算差值。所以我们就计算并返回均方误差数。
下面列出了完整的功能。
# evaluate an ARIMA model for a given order (p,d,q)
def evaluate_arima_model(X, arima_order):
# prepare training dataset
train_size = int(len(X) * 0.66)
train, test = X[0:train_size], X[train_size:]
history = [x for x in train]
# make predictions
predictions = list()
for t in range(len(test)):
model = ARIMA(history, order=arima_order)
model_fit = model.fit(disp=0)
yhat = model_fit.forecast()[0]
predictions.append(yhat)
history.append(test[t])
# calculate out of sample error
error = mean_squared_error(test, predictions)
return error
现在我们已经知道如何评估一组ARIMA超参数,那接下来让我们来看看如何重复调用这个函数来对参数网格进行评估。
评估一套参数是相对比较简单的。
用户必须指定p,d和q ARIMA参数的网格来迭代计算。并为每个参数创建一个模型,通过调用前一节中提到的evaluate_arima_model()函数来评估其性能。
该函数必须跟踪观察到的最低误差分数并记录它的配置参数。我们可以在函数末尾加个打印功能将这些信息打印到标准输出上(默认直接打印到屏幕)。
我们可以将这个名为evaluate_models()的函数实现这个功能,这个函数包含四个循环的。
还要考虑两个额外的问题。首先是确保输入数据是浮点值(而不是整数或字符串),如果不是浮点值这可能导致ARIMA过程失败。
其次,统计模型ARIMA程序内部使用数值优化程序为模型找到一组系数。这些程序可能会失败,还可能会引发异常。我们必须捕获这些异常并跳过导致问题的配置。出现的异常次数可能远远超出你的想象。
此外,建议对此代码忽略警告,以避免运行过程产生大量干扰信息。完成代码如下:
import warnings
warnings.filterwarnings("ignore")
最后,即使有了所有这些保护措施,底层的C和Fortran库仍然会有警告输出,例如:
** On entry to DLASCL, parameter number 4 had an illegal value
为简洁起见,这些告警内容已从本教程中报告的结果中删除。 下面列出了评估ARIMA超参数网格的完整过程。
# evaluate combinations of p, d and q values for an ARIMA model
def evaluate_models(dataset, p_values, d_values, q_values):
dataset = dataset.astype('float32')
best_score, best_cfg = float("inf"), None
for p in p_values:
for d in d_values:
for q in q_values:
order = (p,d,q)
try:
mse = evaluate_arima_model(dataset, order)
if mse < best_score:
best_score, best_cfg = mse, order
print('ARIMA%s MSE=%.3f' % (order,mse))
except:
continue
print('Best ARIMA%s MSE=%.3f' % (best_cfg, best_score))
现在我们就有一个网格搜索ARIMA超参数的程序,让我们来测试两个单变量时间序列问题的过程。
我们将从洗发水销售数据集开始。
洗发水销售数据集包括了3年内洗发水的月销售数量。
这些数据的单位是一个销售计数,有36个数据点。原始数据集归功于Makridakis,Wheelwright和Hyndman(1998)等人的收集工作。
下载数据集并将其放置到当前工作目录中,文件名为 “ shampoo-sales.csv ”。
数据的时间轴并没有给出年份。所以我们可以使用自定义的日期分析函数加载数据和基准年(从1900年开始),如下所示:
# load dataset
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True,date_parser=parser)
加载成功后,我们就可以指定一个p,d和q值的位置来搜索并传递给evaluate_models()函数。
我们将尝试一套滞后值(p)和几个差异迭代(d)和残差滞后值(q)。
# evaluate parameters
p_values = [0, 1, 2, 4, 6, 8, 10]
d_values = range(0, 3)
q_values = range(0, 3)
warnings.filterwarnings("ignore")
evaluate_models(series.values, p_values, d_values, q_values)
将这一切与上一节定义的通用函数联合使用,我们可以在洗发水销售数据集中网格搜索ARIMA超参数。
完整的代码示例如下所示。
import warnings
from pandas import read_csv
from pandas import datetime
from statsmodels.tsa.arima_model import ARIMA
from sklearn.metrics import mean_squared_error
# evaluate an ARIMA model for a given order (p,d,q)
def evaluate_arima_model(X, arima_order):
# 读取测试集数据
train_size = int(len(X) * 0.66)
train, test = X[0:train_size], X[train_size:]
history = [x for x in train]
# 预测
predictions = list()
for t in range(len(test)):
model = ARIMA(history, order=arima_order)
model_fit = model.fit(disp=0)
yhat = model_fit.forecast()[0]
predictions.append(yhat)
history.append(test[t])
# calculate out of sample error
error = mean_squared_error(test, predictions)
return error
# evaluate combinations of p, d and q values for an ARIMA model
def evaluate_models(dataset, p_values, d_values, q_values):
dataset = dataset.astype('float32')
best_score, best_cfg = float("inf"), None
for p in p_values:
for d in d_values:
for q in q_values:
order = (p,d,q)
try:
mse = evaluate_arima_model(dataset, order)
if mse < best_score:
best_score, best_cfg = mse, order
print('ARIMA%s MSE=%.3f' % (order,mse))
except:
continue
print('Best ARIMA%s MSE=%.3f' % (best_cfg, best_score))
# load dataset
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
series = read_csv('shampoo-sales.csv', header=0, parse_dates=[0], index_col=0, squeeze=True, date_parser=parser)
# evaluate parameters
p_values = [0, 1, 2, 4, 6, 8, 10]
d_values = range(0, 3)
q_values = range(0, 3)
warnings.filterwarnings("ignore")
evaluate_models(series.values, p_values, d_values, q_values)
运行该示例将打印每个成功完成评估的ARIMA参数和均方差(MSE)。
在运行结束时报告ARIMA(4,2,1)的最佳参数,均方误差为4,694.873。
ARIMA(0, 0, 0) MSE=52425.268
ARIMA(0, 0, 1) MSE=38145.167
ARIMA(0, 0, 2) MSE=23989.567
ARIMA(0, 1, 0) MSE=18003.173
ARIMA(0, 1, 1) MSE=9558.410
ARIMA(0, 2, 0) MSE=67339.808
ARIMA(0, 2, 1) MSE=18323.163
ARIMA(1, 0, 0) MSE=23112.958
ARIMA(1, 1, 0) MSE=7121.373
ARIMA(1, 1, 1) MSE=7003.683
ARIMA(1, 2, 0) MSE=18607.980
ARIMA(2, 1, 0) MSE=5689.932
ARIMA(2, 1, 1) MSE=7759.707
ARIMA(2, 2, 0) MSE=9860.948
ARIMA(4, 1, 0) MSE=6649.594
ARIMA(4, 1, 1) MSE=6796.279
ARIMA(4, 2, 0) MSE=7596.332
ARIMA(4, 2, 1) MSE=4694.873
ARIMA(6, 1, 0) MSE=6810.080
ARIMA(6, 2, 0) MSE=6261.107
ARIMA(8, 0, 0) MSE=7256.028
ARIMA(8, 1, 0) MSE=6579.403
Best ARIMA(4, 2, 1) MSE=4694.873
“每日女性出生”数据集是来自1959年加州每天的女性出生人数。
单位是计数单位,有365数据点。数据集的来源归功于Newton(1988)。
下载数据集并将其放在当前工作目录中,文件名为 “ daily-total-female-births.csv ”。
这个数据集可以直接作为Pandas Series轻松读取。
# load dataset
series = Series.from_csv('daily-total-female-births.csv', header=0)
为了简单起见,我们将探索与上一节中相同的ARIMA超参数网格。
# evaluate parameters
p_values = [0, 1, 2, 4, 6, 8, 10]
d_values = range(0, 3)
q_values = range(0, 3)
warnings.filterwarnings("ignore")
evaluate_models(series.values, p_values, d_values, q_values)
我们将前面的函数联合使用,我们就可以在“每日女性出生”数据集中网格搜索ARIMA参数。下面提供了完整的代码。
import warnings
from pandas import Series
from statsmodels.tsa.arima_model import ARIMA
from sklearn.metrics import mean_squared_error
# evaluate an ARIMA model for a given order (p,d,q)
def evaluate_arima_model(X, arima_order):
# prepare training dataset
train_size = int(len(X) * 0.66)
train, test = X[0:train_size], X[train_size:]
history = [x for x in train]
# 预测
predictions = list()
for t in range(len(test)):
model = ARIMA(history, order=arima_order)
model_fit = model.fit(disp=0)
yhat = model_fit.forecast()[0]
predictions.append(yhat)
history.append(test[t])
# calculate out of sample error
error = mean_squared_error(test, predictions)
return error
# evaluate combinations of p, d and q values for an ARIMA model
def evaluate_models(dataset, p_values, d_values, q_values):
dataset = dataset.astype('float32')
best_score, best_cfg = float("inf"), None
for p in p_values:
for d in d_values:
for q in q_values:
order = (p,d,q)
try:
mse = evaluate_arima_model(dataset, order)
if mse < best_score:
best_score, best_cfg = mse, order
print('ARIMA%s MSE=%.3f' % (order,mse))
except:
continue
print('Best ARIMA%s MSE=%.3f' % (best_cfg, best_score))
# 读取数据
series = Series.from_csv('daily-total-female-births.csv', header=0)
# evaluate parameters
p_values = [0, 1, 2, 4, 6, 8, 10]
d_values = range(0, 3)
q_values = range(0, 3)
warnings.filterwarnings("ignore")
evaluate_models(series.values, p_values, d_values, q_values)
运行该示例打印每个配置成功评估的ARIMA参数和均方根误差。
最好的平均参数被报道为ARIMA(6,1,0),均方误差为53.187。
ARIMA(0, 0, 0) MSE=67.063
ARIMA(0, 0, 1) MSE=62.165
ARIMA(0, 0, 2) MSE=60.386
ARIMA(0, 1, 0) MSE=84.038
ARIMA(0, 1, 1) MSE=56.653
ARIMA(0, 1, 2) MSE=55.272
ARIMA(0, 2, 0) MSE=246.414
ARIMA(0, 2, 1) MSE=84.659
ARIMA(1, 0, 0) MSE=60.876
ARIMA(1, 1, 0) MSE=65.928
ARIMA(1, 1, 1) MSE=55.129
ARIMA(1, 1, 2) MSE=55.197
ARIMA(1, 2, 0) MSE=143.755
ARIMA(2, 0, 0) MSE=59.251
ARIMA(2, 1, 0) MSE=59.487
ARIMA(2, 1, 1) MSE=55.013
ARIMA(2, 2, 0) MSE=107.600
ARIMA(4, 0, 0) MSE=59.189
ARIMA(4, 1, 0) MSE=57.428
ARIMA(4, 1, 1) MSE=55.862
ARIMA(4, 2, 0) MSE=80.207
ARIMA(6, 0, 0) MSE=58.773
ARIMA(6, 1, 0) MSE=53.187
ARIMA(6, 1, 1) MSE=57.055
ARIMA(6, 2, 0) MSE=69.753
ARIMA(8, 0, 0) MSE=56.984
ARIMA(8, 1, 0) MSE=57.290
ARIMA(8, 2, 0) MSE=66.034
ARIMA(8, 2, 1) MSE=57.884
ARIMA(10, 0, 0) MSE=57.470
ARIMA(10, 1, 0) MSE=57.359
ARIMA(10, 2, 0) MSE=65.503
ARIMA(10, 2, 1) MSE=57.878
ARIMA(10, 2, 2) MSE=58.309
Best ARIMA(6, 1, 0) MSE=53.187
本教程中使用的网格搜索方法很简单,可以很容易地扩展。
本节列出了一些想法来扩展您可能希望探索的方法。
在本教程中,您了解了如何使用Python超参数的网格搜索ARIMA模型。
具体来说,你了解到:
现在就要你自己动手做实验了。