Cómo realizar una búsqueda en cuadrícula de hiperparámetros del modelo ARIMA con Python
El modelo ARIMA para análisis y pronóstico de series temporales puede resultar complicado de configurar.
Hay tres parámetros que requieren una estimación mediante prueba y error iterativos a partir de la revisión de gráficos de diagnóstico y el uso de reglas heurísticas de hace 40 años.
Podemos automatizar el proceso de evaluación de una gran cantidad de hiperparámetros para el modelo ARIMA mediante el uso de un procedimiento de búsqueda de cuadrícula.
En este tutorial, descubrirá cómo ajustar el modelo ARIMA mediante una búsqueda de cuadrícula de hiperparámetros en Python.
Después de completar este tutorial, sabrá:
- Un procedimiento general que puede utilizar para ajustar los hiperparámetros ARIMA para un pronóstico continuo de un solo paso.
- Cómo aplicar la optimización de hiperparámetros ARIMA en un conjunto de datos de series temporales univariadas estándar.
- Ideas para ampliar el procedimiento a modelos más elaborados y robustos.
Pon en marcha tu proyecto con mi nuevo libro Time Series Forecasting With Python, que incluye tutoriales paso a paso y los archivos de código fuente de Python para todos los ejemplos.
Empecemos.
- Actualizado en abril de 2019: se actualizaron los enlaces a los conjuntos de datos.
- Actualizado en agosto de 2019: carga de datos actualizada para usar la nueva API.
- Actualizado en diciembre de 2020: modelado actualizado para cambios en la API.
Método de búsqueda de cuadrícula
Se pueden utilizar gráficos de diagnóstico de series temporales junto con reglas heurísticas para determinar los hiperparámetros del modelo ARIMA.
Estos son buenos en la mayoría de las situaciones, pero quizás no en todas.
Podemos automatizar el proceso de entrenamiento y evaluación de modelos ARIMA en diferentes combinaciones de hiperparámetros del modelo. En el aprendizaje automático, esto se denomina búsqueda de cuadrícula o ajuste de modelo.
En este tutorial, desarrollaremos un método para buscar en cuadrícula hiperparámetros ARIMA para un pronóstico continuo de un solo paso.
El enfoque se divide en dos partes:
- Evaluar un modelo ARIMA.
- Evaluar conjuntos de parámetros ARIMA.
El código de este tutorial utiliza las bibliotecas Python scikit-learn, Pandas y statsmodels.
1. Evaluar el modelo ARIMA
Podemos evaluar un modelo ARIMA preparándolo en un conjunto de datos de entrenamiento y evaluando predicciones en un conjunto de datos de prueba.
Este enfoque implica los siguientes pasos:
- Divida el conjunto de datos en conjuntos de entrenamiento y prueba.
Recorra los pasos de tiempo en el conjunto de datos de prueba.
- Entrene un modelo ARIMA.
- Haz una predicción de un paso.
- Predicción de la tienda; obtener y almacenar observaciones reales.
Podemos implementar esto en Python como una nueva función independiente llamada evaluate_arima_model() que toma un conjunto de datos de series temporales como entrada, así como una tupla con p, d. y q parámetros para el modelo a evaluar.
El conjunto de datos se divide en dos: el 66 % para el conjunto de datos de entrenamiento inicial y el 34 % restante para el conjunto de datos de prueba.
Se itera cada paso de tiempo del conjunto de prueba. Una sola iteración proporciona un modelo que se puede utilizar para hacer predicciones sobre datos nuevos. El enfoque iterativo permite entrenar un nuevo modelo ARIMA en cada paso de tiempo.
En cada iteración se realiza una predicción y se almacena en una lista. Esto es para que al final del conjunto de pruebas, todas las predicciones puedan compararse con la lista de valores esperados y calcularse una puntuación de error. En este caso, se calcula y devuelve una puntuación de error cuadrático medio.
La función completa se enumera a continuación.
# 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()
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
Ahora que sabemos cómo evaluar un conjunto de hiperparámetros ARIMA, veamos cómo podemos llamar a esta función repetidamente para evaluar una cuadrícula de parámetros.
2. Iterar los parámetros ARIMA
Evaluar un conjunto de parámetros es relativamente sencillo.
El usuario debe especificar una cuadrícula de parámetros ARIMA p, d y q para iterar. Se crea un modelo para cada parámetro y se evalúa su rendimiento llamando a la función evaluate_arima_model() descrita en la sección anterior.
La función debe realizar un seguimiento de la puntuación de error más baja observada y la configuración que la provocó. Esto se puede resumir al final de la función con una impresión estándar.
Podemos implementar esta función llamada evaluate_models() como una serie de cuatro bucles.
Hay dos consideraciones adicionales. La primera es garantizar que los datos de entrada sean valores de punto flotante (a diferencia de números enteros o cadenas), ya que esto puede provocar que el procedimiento ARIMA falle.
En segundo lugar, el procedimiento ARIMA de statsmodels utiliza internamente procedimientos de optimización numérica para encontrar un conjunto de coeficientes para el modelo. Estos procedimientos pueden fallar, lo que a su vez puede generar una excepción. Debemos detectar estas excepciones y omitir aquellas configuraciones que causan un problema. Esto sucede con más frecuencia de lo que piensas.
Además, se recomienda ignorar las advertencias de este código para evitar mucho ruido al ejecutar el procedimiento. Esto se puede hacer de la siguiente manera:
import warnings
warnings.filterwarnings("ignore")
Finalmente, incluso con todas estas protecciones, las bibliotecas subyacentes de C y Fortran aún pueden informar advertencias sobre el estándar, como por ejemplo:
** On entry to DLASCL, parameter number 4 had an illegal value
Estos se han eliminado de los resultados informados en este tutorial por motivos de brevedad.
El procedimiento completo para evaluar una cuadrícula de hiperparámetros ARIMA se enumera a continuación.
# 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))
Ahora que tenemos un procedimiento para buscar hiperparámetros ARIMA en una cuadrícula, probemos el procedimiento en dos problemas de series temporales univariadas.
Comenzaremos con el conjunto de datos de Shampoo Sales.
Estudio de caso de venta de champú
El conjunto de datos de Shampoo Sales describe el número mensual de ventas de champú durante un período de 3 años.
Las unidades son un conteo de ventas y hay 36 observaciones. El conjunto de datos original se atribuye a Makridakis, Wheelwright y Hyndman (1998).
- Descargue el conjunto de datos.
Descargue el conjunto de datos y colóquelo en su directorio de trabajo actual con el nombre de archivo "shampoo-sales.csv".
Las marcas de tiempo de la serie temporal no contienen un componente de año absoluto. Podemos usar una función personalizada de análisis de fechas al cargar los datos y establecer la línea base del año desde 1900, de la siguiente manera:
# 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)
Una vez cargado, podemos especificar un sitio con valores p, d y q para buscar y pasarlos a evaluate_models(). función .
Probaremos un conjunto de valores de retraso (p) y solo unas pocas iteraciones de diferencia (d) y valores de retraso de error residual (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)
Al combinar todo esto con los procedimientos genéricos definidos en la sección anterior, podemos buscar en cuadrícula los hiperparámetros ARIMA en el conjunto de datos de Shampoo Sales.
El ejemplo de código completo se enumera a continuación.
# grid search ARIMA parameters for time series
import warnings
from math import sqrt
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):
# 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()
yhat = model_fit.forecast()[0]
predictions.append(yhat)
history.append(test[t])
# calculate out of sample error
rmse = sqrt(mean_squared_error(test, predictions))
return rmse
# 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:
rmse = evaluate_arima_model(dataset, order)
if rmse < best_score:
best_score, best_cfg = rmse, order
print('ARIMA%s RMSE=%.3f' % (order,rmse))
except:
continue
print('Best ARIMA%s RMSE=%.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, index_col=0, parse_dates=True, 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)
Al ejecutar el ejemplo se imprimen los parámetros ARIMA y MSE para cada evaluación completada exitosamente.
Los mejores parámetros de ARIMA(4, 2, 1) se informan al final de la ejecución con un error cuadrático medio de 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
Estudio de caso de nacimientos diarios de mujeres
El conjunto de datos Daily Female Births describe el número de nacimientos diarios de mujeres en California en 1959.
Las unidades son un conteo y hay 365 observaciones. La fuente del conjunto de datos se atribuye a Newton (1988).
- Descargue el conjunto de datos.
Descargue el conjunto de datos y colóquelo en su directorio de trabajo actual con el nombre de archivo “daily-total-female-births.csv“.
Este conjunto de datos se puede cargar fácilmente y directamente como una serie Pandas.
# load dataset
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
Para simplificar las cosas, exploraremos la misma cuadrícula de hiperparámetros ARIMA que en la sección anterior.
# 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)
Juntando todo esto, podemos buscar en la cuadrícula los parámetros ARIMA en el conjunto de datos de Nacimientos femeninos diarios. La lista completa de códigos se proporciona a continuación.
# grid search ARIMA parameters for time series
import warnings
from math import sqrt
from pandas import read_csv
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]
# make predictions
predictions = list()
for t in range(len(test)):
model = ARIMA(history, order=arima_order)
model_fit = model.fit()
yhat = model_fit.forecast()[0]
predictions.append(yhat)
history.append(test[t])
# calculate out of sample error
rmse = sqrt(mean_squared_error(test, predictions))
return rmse
# 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:
rmse = evaluate_arima_model(dataset, order)
if rmse < best_score:
best_score, best_cfg = rmse, order
print('ARIMA%s RMSE=%.3f' % (order,rmse))
except:
continue
print('Best ARIMA%s RMSE=%.3f' % (best_cfg, best_score))
# load dataset
series = read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True, squeeze=True)
# 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)
Al ejecutar el ejemplo se imprimen los parámetros ARIMA y el error cuadrático medio para cada configuración evaluada correctamente.
Los mejores parámetros medios se informan como ARIMA(6, 1, 0) con un error cuadrático medio de 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
Extensiones
El método de búsqueda en cuadrícula utilizado en este tutorial es simple y se puede ampliar fácilmente.
Esta sección enumera algunas ideas para ampliar el enfoque que quizás desee explorar.
- Cuadrícula de semillas. Las herramientas de diagnóstico clásicas de los gráficos ACF y PACF aún se pueden usar con los resultados utilizados para generar la cuadrícula de parámetros ARIMA para buscar.
- Medidas alternativas. La búsqueda busca optimizar el error cuadrático medio fuera de muestra. Esto podría cambiarse por otra estadística fuera de la muestra, una estadística dentro de la muestra, como AIC o BIC, o alguna combinación de ambas. Puede elegir la métrica que sea más significativa para su proyecto.
- Diagnóstico residual. Se pueden calcular automáticamente estadísticas sobre los errores de pronóstico residuales para proporcionar una indicación adicional de la calidad del ajuste. Los ejemplos incluyen pruebas estadísticas para determinar si la distribución de los residuos es gaussiana y si existe una autocorrelación en los residuos.
- Actualizar modelo. El modelo ARIMA se crea desde cero para cada pronóstico de un paso. Con una inspección cuidadosa de la API, es posible actualizar los datos internos del modelo con nuevas observaciones en lugar de recrearlo desde cero.
- Condiciones previas. El modelo ARIMA puede hacer suposiciones sobre el conjunto de datos de series temporales, como normalidad y estacionariedad. Estos podrían verificarse y generarse una advertencia para un determinado conjunto de datos antes de entrenar un modelo determinado.
Resumen
En este tutorial, descubrió cómo realizar una búsqueda en cuadrícula de los hiperparámetros para el modelo ARIMA en Python.
Específicamente, aprendiste:
- Un procedimiento que puede utilizar para buscar en cuadrícula hiperparámetros ARIMA para un pronóstico continuo de un solo paso.
- Cómo aplicar el ajuste de hiperparámetros ARIMA en conjuntos de datos de series temporales univariadas estándar.
- Ideas sobre cómo mejorar aún más la búsqueda en cuadrícula de hiperparámetros ARIMA.
Ahora es tu turno.
Pruebe este procedimiento en su conjunto de datos de series temporales favorito. ¿Qué resultados obtuviste?
Informe sus resultados en los comentarios a continuación.
¿Tiene alguna pregunta?
Haga sus preguntas en los comentarios a continuación y haré todo lo posible para responder.