Comment rechercher sur une grille les hyperparamètres du modèle ARIMA avec Python
Le modèle ARIMA pour l'analyse et la prévision de séries chronologiques peut être difficile à configurer.
Il existe 3 paramètres qui nécessitent une estimation par essais et erreurs itératifs à partir de l'examen des graphiques de diagnostic et de l'utilisation de règles heuristiques vieilles de 40 ans.
Nous pouvons automatiser le processus d'évaluation d'un grand nombre d'hyperparamètres pour le modèle ARIMA en utilisant une procédure de recherche de grille.
Dans ce didacticiel, vous découvrirez comment régler le modèle ARIMA à l'aide d'une recherche par grille d'hyperparamètres en Python.
Après avoir terminé ce tutoriel, vous saurez :
- Procédure générale que vous pouvez utiliser pour régler les hyperparamètres ARIMA pour une prévision glissante en une étape.
- Comment appliquer l'optimisation des hyperparamètres ARIMA sur un ensemble de données de séries chronologiques univariées standard.
- Idées pour étendre la procédure à des modèles plus élaborés et plus robustes.
Démarrez votre projet avec mon nouveau livre Time Series Forecasting With Python, comprenant des tutoriels étape par étape et les fichiers code source Python pour tous les exemples.
Commençons.
- Mise à jour en avril 2019 : mise à jour des liens vers les ensembles de données.
- Mise à jour en août 2019 : chargement des données mis à jour pour utiliser la nouvelle API.
- Mise à jour en décembre 2020 : modélisation mise à jour pour les modifications apportées à l'API.
Méthode de recherche de grille
Les tracés de diagnostic de la série chronologique peuvent être utilisés avec des règles heuristiques pour déterminer les hyperparamètres du modèle ARIMA.
Ceux-ci sont bons dans la plupart des situations, mais peut-être pas dans toutes.
Nous pouvons automatiser le processus de formation et d'évaluation des modèles ARIMA sur différentes combinaisons d'hyperparamètres de modèle. En apprentissage automatique, cela s'appelle une recherche de grille ou un réglage de modèle.
Dans ce didacticiel, nous développerons une méthode de recherche sur grille des hyperparamètres ARIMA pour une prévision glissante en une étape.
La démarche se décompose en deux parties :
- Évaluer un modèle ARIMA.
- Évaluer des ensembles de paramètres ARIMA.
Le code de ce didacticiel utilise les bibliothèques Python scikit-learn, Pandas et statsmodels.
1. Évaluer le modèle ARIMA
Nous pouvons évaluer un modèle ARIMA en le préparant sur un ensemble de données d'entraînement et en évaluant les prédictions sur un ensemble de données de test.
Cette approche implique les étapes suivantes :
- Divisez l'ensemble de données en ensembles de formation et de test.
Parcourez les pas de temps dans l’ensemble de données de test.
- Former un modèle ARIMA.
- Faites une prédiction en une étape.
- Prédiction du magasin ; obtenir et stocker l’observation réelle.
Nous pouvons implémenter cela en Python en tant que nouvelle fonction autonome appelée evaluate_arima_model() qui prend un ensemble de données de série chronologique en entrée ainsi qu'un tuple avec le p, d et q pour le modèle à évaluer.
L'ensemble de données est divisé en deux : 66 % pour l'ensemble de données de formation initiale et les 34 % restants pour l'ensemble de données de test.
Chaque pas de temps de l’ensemble de test est itéré. Une seule itération fournit un modèle que vous pouvez utiliser pour faire des prédictions sur de nouvelles données. L'approche itérative permet d'entraîner un nouveau modèle ARIMA à chaque pas de temps.
Une prédiction est effectuée à chaque itération et stockée dans une liste. Ainsi, à la fin de l'ensemble de tests, toutes les prédictions peuvent être comparées à la liste des valeurs attendues et un score d'erreur calculé. Dans ce cas, un score d’erreur quadratique moyenne est calculé et renvoyé.
La fonction complète est répertoriée ci-dessous.
# 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
Maintenant que nous savons comment évaluer un ensemble d’hyperparamètres ARIMA, voyons comment appeler cette fonction à plusieurs reprises pour évaluer une grille de paramètres.
2. Itérer les paramètres ARIMA
L’évaluation d’une suite de paramètres est relativement simple.
L'utilisateur doit spécifier une grille de paramètres ARIMA p, d et q pour itérer. Un modèle est créé pour chaque paramètre et ses performances sont évaluées en appelant la fonction evaluate_arima_model() décrite dans la section précédente.
La fonction doit garder une trace du score d'erreur le plus bas observé et de la configuration qui l'a provoqué. Ceci peut être résumé à la fin de la fonction avec une impression vers la sortie standard.
Nous pouvons implémenter cette fonction appelée evaluate_models() sous la forme d'une série de quatre boucles.
Il y a deux considérations supplémentaires. La première consiste à s'assurer que les données d'entrée sont des valeurs à virgule flottante (par opposition à des entiers ou des chaînes), car cela peut entraîner l'échec de la procédure ARIMA.
Deuxièmement, la procédure ARIMA des modèles de statistiques utilise en interne des procédures d'optimisation numérique pour trouver un ensemble de coefficients pour le modèle. Ces procédures peuvent échouer, ce qui peut générer une exception. Nous devons détecter ces exceptions et ignorer les configurations qui posent problème. Cela arrive plus souvent qu’on ne le pense.
De plus, il est recommandé d’ignorer les avertissements pour ce code afin d’éviter beaucoup de bruit lors de l’exécution de la procédure. Cela peut être fait comme suit :
import warnings
warnings.filterwarnings("ignore")
Enfin, même avec toutes ces protections, les bibliothèques C et Fortran sous-jacentes peuvent toujours signaler des avertissements au standard, tels que :
** On entry to DLASCL, parameter number 4 had an illegal value
Ceux-ci ont été supprimés des résultats rapportés dans ce didacticiel par souci de concision.
La procédure complète d'évaluation d'une grille d'hyperparamètres ARIMA est répertoriée ci-dessous.
# 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))
Maintenant que nous disposons d'une procédure pour rechercher sur une grille les hyperparamètres ARIMA, testons la procédure sur deux problèmes de séries temporelles univariées.
Nous commencerons par l’ensemble de données Shampoo Sales.
Étude de cas sur les ventes de shampoings
L'ensemble de données Shampoo Sales décrit le nombre mensuel de ventes de shampooing sur une période de 3 ans.
Les unités sont un décompte des ventes et il y a 36 observations. L'ensemble de données original est attribué à Makridakis, Wheelwright et Hyndman (1998).
- Téléchargez l'ensemble de données.
Téléchargez l'ensemble de données et placez-le dans votre répertoire de travail actuel avec le nom de fichier « shampoo-sales.csv ».
Les horodatages de la série chronologique ne contiennent pas de composante d’année absolue. Nous pouvons utiliser une fonction d'analyse de date personnalisée lors du chargement des données et de l'année de référence à partir de 1900, comme suit :
# 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)
Une fois chargé, nous pouvons spécifier un site de valeurs p, d et q pour les rechercher et les transmettre à evaluate_models() fonction.
Nous allons essayer une suite de valeurs de décalage (p) et juste quelques itérations différentes (d) et des valeurs de décalage d'erreur résiduelles (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)
En associant tout cela aux procédures génériques définies dans la section précédente, nous pouvons rechercher dans une grille les hyperparamètres ARIMA dans l'ensemble de données Shampoo Sales.
L’exemple de code complet est répertorié ci-dessous.
# 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)
L’exécution de l’exemple imprime les paramètres ARIMA et MSE pour chaque évaluation réussie terminée.
Les meilleurs paramètres d'ARIMA(4, 2, 1) sont rapportés à la fin de l'exécution avec une erreur quadratique moyenne 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
Étude de cas sur les naissances quotidiennes de femmes
L'ensemble de données Daily Female Births décrit le nombre de naissances quotidiennes de femmes en Californie en 1959.
Les unités sont un décompte et il y a 365 observations. La source de l'ensemble de données est attribuée à Newton (1988).
- Téléchargez l'ensemble de données.
Téléchargez l'ensemble de données et placez-le dans votre répertoire de travail actuel avec le nom de fichier « daily-total-female-births.csv ».
Cet ensemble de données peut être facilement chargé directement en tant que série Pandas.
# load dataset
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
Pour simplifier les choses, nous explorerons la même grille d'hyperparamètres ARIMA que dans la section précédente.
# 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)
En mettant tout cela ensemble, nous pouvons rechercher dans une grille les paramètres ARIMA sur l'ensemble de données des naissances quotidiennes féminines. La liste complète des codes est fournie ci-dessous.
# 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)
L’exécution de l’exemple imprime les paramètres ARIMA et l’erreur quadratique moyenne pour chaque configuration évaluée avec succès.
Les meilleurs paramètres moyens sont indiqués sous la forme ARIMA (6, 1, 0) avec une erreur quadratique moyenne 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
Rallonges
La méthode de recherche par grille utilisée dans ce didacticiel est simple et peut facilement être étendue.
Cette section répertorie quelques idées pour étendre l’approche que vous souhaiterez peut-être explorer.
- Grille de semences. Les outils de diagnostic classiques des tracés ACF et PACF peuvent toujours être utilisés avec les résultats utilisés pour ensemencer la grille de paramètres ARIMA à rechercher.
- Mesures alternatives. La recherche vise à optimiser l’erreur quadratique moyenne hors échantillon. Cela pourrait être remplacé par une autre statistique hors échantillon, une statistique dans l'échantillon, telle que AIC ou BIC, ou une combinaison des deux. Vous pouvez choisir une métrique la plus significative pour votre projet.
- Diagnostics résiduels. Des statistiques peuvent être automatiquement calculées sur les erreurs de prévision résiduelles pour fournir une indication supplémentaire sur la qualité de l'ajustement. Les exemples incluent des tests statistiques pour savoir si la distribution des résidus est gaussienne et s'il existe une autocorrélation dans les résidus.
- Mettre à jour le modèle. Le modèle ARIMA est créé à partir de zéro pour chaque prévision en une étape. Avec une inspection minutieuse de l'API, il peut être possible de mettre à jour les données internes du modèle avec de nouvelles observations plutôt que de le recréer à partir de zéro.
- Conditions préalables. Le modèle ARIMA peut formuler des hypothèses sur l'ensemble de données de séries chronologiques, telles que la normalité et la stationnarité. Ceux-ci pourraient être vérifiés et un avertissement émis pour un ensemble de données donné avant qu'un modèle donné ne soit formé.
Résumé
Dans ce didacticiel, vous avez découvert comment effectuer une recherche sur grille des hyperparamètres du modèle ARIMA en Python.
Concrètement, vous avez appris :
- Procédure que vous pouvez utiliser pour rechercher dans une grille les hyperparamètres ARIMA pour une prévision glissante en une étape.
- Comment appliquer le réglage des hyperparamètres ARIMA sur des ensembles de données de séries chronologiques univariées standard.
- Idées sur la manière d'améliorer encore la recherche dans la grille des hyperparamètres ARIMA.
Maintenant c'est votre tour.
Essayez cette procédure sur votre ensemble de données de série chronologique préféré. Quels résultats avez-vous obtenus ?
Signalez vos résultats dans les commentaires ci-dessous.
Avez-vous des questions ?
Posez vos questions dans les commentaires ci-dessous et je ferai de mon mieux pour y répondre.