如何使用Python超参数的网格搜索ARIMA模型

时间:2022-04-26
本文章向大家介绍如何使用Python超参数的网格搜索ARIMA模型,主要内容包括网格搜索方法、2.迭代ARIMA参数、洗发水销售案例研究、每日女性出生案例研究、扩展、总结、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

我们都知道用于时序分析和预测的ARIMA模型可能很难配置。

需要通过反复地审查诊断图和已经使用了40多年的启发式策略中训练并修正三个参数的错误。

我们可以通过使用网格搜索过程来自动化评估ARIMA模型的大量超参数的过程。

在本教程中,您将了解如何使用Python中的超参数网格搜索来调整ARIMA模型。

完成本教程后,您将知道:

  • 您可以使用一般程序来调整ARIMA的超参数以进行滚动式一步预测(rolling one-step forecast)。
  • 如何在标准单变量时间序列数据上应用ARIMA超参数优化。
  • 扩展更精细和强大的模型程序的思路。

让我们开始吧。

此图与文章无关

网格搜索方法

时间序列的诊断图可以与启发式策略一起使用以确定ARIMA模型的超参数。

他们可以大多数都可以确定ARIMA模型的参数,但有的时候不能确定。

我们可以使用不同的模型超参数的组合来自动化训练和评估ARIMA模型。在机器学习中,这被称为网格搜索或模型调整。

在本教程中,我们将开发一种网格搜索ARIMA超参数的单步滚动预测方法。

该方法分为两部分:

  1. 评估一个ARIMA模型。
  2. 评估一组ARIMA参数。

本教程中的代码使用Python库是scikit-learn,Pandas和statsmodels。

1.评估ARIMA模型

我们可以通过在训练数据集上准备ARIMA模型并评估测试数据集的预测来评估ARIMA模型。

这种方法涉及以下步骤:

  1. 将数据集分解为训练集和测试集。
  2. 按测试数据集中的时间序列进行预测。
    1. 训练一个ARIMA模型。
    2. 做一个一步的预测。
    3. 存储预测结果; 获取并存储实际观察结果。
  3. 计算与预期值的误差。

我们可以在Python中将其实现为一个新的独立函数,名为evaluate_arima_model(),它将时间序列数据集作为输入,以及具有pdq参数的元组作为输入。

数据集分为两部分:初始训练数据集为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超参数,那接下来让我们来看看如何重复调用这个函数来对参数网格进行评估。

2.迭代ARIMA参数

评估一套参数是相对比较简单的。

用户必须指定pdq 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)

加载成功后,我们就可以指定一个pdq值的位置来搜索并传递给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

扩展

本教程中使用的网格搜索方法很简单,可以很容易地扩展。

本节列出了一些想法来扩展您可能希望探索的方法。

  • 种子网格(Seed Grid)。ACF(Auto Correlation Function)和PACF图的经典诊断工具仍然可以与用于搜索ARIMA参数网格的结果一起使用。
  • 备用措施(Alternate Measures)。该搜索将通过优化样本外均方误差。这可以更改为另一个样本外统计量,样本统计量,如AIC(Akaike information criterion)或BIC(Bayesian Information Criterion),或两者的组合。您可以选择对您的项目最有意义的指标。
  • 残差诊断(Residual Diagnostics)。统计数据可以自动计算残差,以提供合适的额外预测。例子包括残差分布是否为高斯的统计检验,以及残差是否存在自相关。
  • 更新模型(Update Model)。ARIMA模型是从头开始为每个单步预测创建的。通过仔细检查API,可以用新的观察值更新模型的内部数据,而不是从头开始重新创建。
  • 先决条件(Preconditions)。ARIMA模型可以对时间序列数据集进行假设,例如正态性和平稳性方面的假设。在给定的模型被训练之前,可以对这些数据集进行检查并给出警告。

总结

在本教程中,您了解了如何使用Python超参数的网格搜索ARIMA模型。

具体来说,你了解到:

  • 您可以使用网格搜索ARIMA超参数进行单步滚动预测的过程。
  • 如何应用ARIMA超参数调整标准单变量时间序列数据集。
  • 关于如何进一步改进ARIMA超参数网格搜索的思路。

现在就要你自己动手做实验了。