Une introduction douce à la marche aléatoire pour la prévision de séries temporelles avec Python
Comment savoir si votre problème de série chronologique est prévisible ?
C’est une question difficile avec la prévision de séries chronologiques. Il existe un outil appelé marche aléatoire qui peut vous aider à comprendre la prévisibilité de votre problème de prévision de séries chronologiques.
Dans ce tutoriel, vous découvrirez la marche aléatoire et ses propriétés en Python.
Après avoir terminé ce tutoriel, vous saurez :
- Qu'est-ce que la marche aléatoire et comment en créer une à partir de zéro en Python.
- Comment analyser les propriétés d'une marche aléatoire et reconnaître quand une série chronologique est ou non une marche aléatoire.
- Comment faire des prédictions pour une marche aléatoire.
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 septembre 2019 : exemples mis à jour pour utiliser la dernière API.
Série aléatoire
La bibliothèque standard Python contient le module random qui donne accès à une suite de fonctions permettant de générer des nombres aléatoires.
La fonction randrange() peut être utilisée pour générer un entier aléatoire compris entre 0 et une limite supérieure.
Nous pouvons utiliser la fonction randrange() pour générer une liste de 1 000 entiers aléatoires compris entre 0 et 10. L'exemple est répertorié ci-dessous.
from random import seed
from random import randrange
from matplotlib import pyplot
seed(1)
series = [randrange(10) for i in range(1000)]
pyplot.plot(series)
pyplot.show()
L’exécution de l’exemple trace la séquence de nombres aléatoires.
C'est un vrai gâchis. Cela ne ressemble en rien à une série chronologique.
Ce n'est pas une marche aléatoire. C'est juste une séquence de nombres aléatoires.
Une erreur courante que font les débutants est de penser qu’une marche aléatoire est une liste de nombres aléatoires, et ce n’est pas du tout le cas.
Marche aléatoire
Une marche aléatoire est différente d'une liste de nombres aléatoires car la valeur suivante de la séquence est une modification de la valeur précédente de la séquence.
Le processus utilisé pour générer la série force la dépendance d’une étape à l’autre. Cette dépendance offre une certaine cohérence d’une étape à l’autre plutôt que les grands sauts qu’offre une série de nombres aléatoires indépendants.
C’est cette dépendance qui donne au processus son nom de « marche aléatoire » ou de « marche de l’ivrogne ».
Un modèle simple de marche aléatoire est le suivant :
- Commencez par un nombre aléatoire de -1 ou 1.
- Sélectionnez au hasard un -1 ou un 1 et ajoutez-le à l'observation du pas de temps précédent.
- Répétez l'étape 2 aussi longtemps que vous le souhaitez.
De manière plus succincte, nous pouvons décrire ce processus comme suit :
y(t) = B0 + B1*X(t-1) + e(t)
Où y(t) est la valeur suivante de la série. B0 est un coefficient qui, s'il est défini sur une valeur autre que zéro, ajoute une dérive constante à la marche aléatoire. B1 est un coefficient pour pondérer le pas de temps précédent et est défini sur 1,0. X(t-1) est l'observation au pas de temps précédent. e(t) est le bruit blanc ou la fluctuation aléatoire à ce moment-là.
Nous pouvons implémenter cela en Python en parcourant ce processus et en créant une liste de 1 000 pas de temps pour la marche aléatoire. L’exemple complet est répertorié ci-dessous.
from random import seed
from random import random
from matplotlib import pyplot
seed(1)
random_walk = list()
random_walk.append(-1 if random() < 0.5 else 1)
for i in range(1, 1000):
movement = -1 if random() < 0.5 else 1
value = random_walk[i-1] + movement
random_walk.append(value)
pyplot.plot(random_walk)
pyplot.show()
L’exécution de l’exemple crée un tracé linéaire de la marche aléatoire.
Nous pouvons voir que cela semble très différent de notre séquence de nombres aléatoires ci-dessus. En fait, la forme et le mouvement ressemblent à une série chronologique réaliste du prix d’un titre en bourse.
Dans les sections suivantes, nous examinerons de plus près les propriétés d’une marche aléatoire. Ceci est utile car cela vous donnera un contexte pour vous aider à identifier si une série chronologique que vous analyserez à l'avenir pourrait être une marche aléatoire.
Commençons par examiner la structure d’autocorrélation.
Marche aléatoire et autocorrélation
Nous pouvons calculer la corrélation entre chaque observation et les observations aux pas de temps précédents. Un tracé de ces corrélations est appelé tracé d’autocorrélation ou corrélogramme.
Compte tenu de la façon dont la marche aléatoire est construite, nous nous attendrions à une forte autocorrélation avec l’observation précédente et à une diminution linéaire à partir de là avec les valeurs de décalage précédentes.
Nous pouvons utiliser la fonction autocorrelation_plot() dans Pandas pour tracer le corrélogramme de la marche aléatoire.
L’exemple complet est répertorié ci-dessous.
Notez que dans chaque exemple où nous générons la marche aléatoire, nous utilisons la même graine pour le générateur de nombres aléatoires afin de garantir que nous obtenons la même séquence de nombres aléatoires, et donc la même marche aléatoire.
from random import seed
from random import random
from matplotlib import pyplot
from pandas.plotting import autocorrelation_plot
seed(1)
random_walk = list()
random_walk.append(-1 if random() < 0.5 else 1)
for i in range(1, 1000):
movement = -1 if random() < 0.5 else 1
value = random_walk[i-1] + movement
random_walk.append(value)
autocorrelation_plot(random_walk)
pyplot.show()
En prenant l’exemple, nous observons généralement la tendance attendue, dans ce cas sur les premières centaines d’observations de décalage.
Marche aléatoire et stationnarité
Une série chronologique stationnaire est une série dont les valeurs ne sont pas fonction du temps.
Compte tenu de la manière dont la marche aléatoire est construite et des résultats de l’examen de l’autocorrélation, nous savons que les observations d’une marche aléatoire dépendent du temps.
L'observation actuelle est une étape aléatoire par rapport à l'observation précédente.
On peut donc s’attendre à ce qu’une marche aléatoire soit non stationnaire. En fait, tous les processus de marche aléatoire ne sont pas stationnaires. Notez que toutes les séries chronologiques non stationnaires ne sont pas des marches aléatoires.
De plus, une série chronologique non stationnaire n’a pas de moyenne et/ou de variance cohérente dans le temps. Un examen du tracé des lignes de marche aléatoires pourrait suggérer que tel est le cas.
Nous pouvons le confirmer à l’aide d’un test de signification statistique, notamment le test Augmenté de Dickey-Fuller.
Nous pouvons effectuer ce test en utilisant la fonction adfuller() de la bibliothèque statsmodels. L’exemple complet est répertorié ci-dessous.
from random import seed
from random import random
from statsmodels.tsa.stattools import adfuller
# generate random walk
seed(1)
random_walk = list()
random_walk.append(-1 if random() < 0.5 else 1)
for i in range(1, 1000):
movement = -1 if random() < 0.5 else 1
value = random_walk[i-1] + movement
random_walk.append(value)
# statistical test
result = adfuller(random_walk)
print('ADF Statistic: %f' % result[0])
print('p-value: %f' % result[1])
print('Critical Values:')
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
L’hypothèse nulle du test est que la série temporelle est non stationnaire.
En exécutant l’exemple, nous pouvons voir que la valeur statistique du test était de 0,341605. Cette valeur est supérieure à toutes les valeurs critiques aux niveaux de confiance de 1 %, 5 % et 10 %. Par conséquent, nous pouvons dire que la série chronologique semble effectivement non stationnaire et qu’il est peu probable que le résultat soit un hasard statistique.
ADF Statistic: 0.341605
p-value: 0.979175
Critical Values:
5%: -2.864
1%: -3.437
10%: -2.568
Nous pouvons rendre la marche aléatoire stationnaire en prenant la première différence.
Cela remplace chaque observation par la différence entre elle et la valeur précédente.
Compte tenu de la manière dont cette marche aléatoire a été construite, nous nous attendons à ce qu’elle aboutisse à une série chronologique de valeurs -1 et 1. C'est exactement ce que nous voyons.
L’exemple complet est répertorié ci-dessous.
from random import seed
from random import random
from matplotlib import pyplot
# create random walk
seed(1)
random_walk = list()
random_walk.append(-1 if random() < 0.5 else 1)
for i in range(1, 1000):
movement = -1 if random() < 0.5 else 1
value = random_walk[i-1] + movement
random_walk.append(value)
# take difference
diff = list()
for i in range(1, len(random_walk)):
value = random_walk[i] - random_walk[i - 1]
diff.append(value)
# line plot
pyplot.plot(diff)
pyplot.show()
L'exécution de l'exemple produit un tracé linéaire montrant 1 000 mouvements de -1 et 1, un véritable gâchis.
Ce graphique de différence montre également clairement que nous n’avons en réalité aucune information avec laquelle travailler ici autre qu’une série de mouvements aléatoires.
Il n'y a pas de structure à apprendre.
Maintenant que la série temporelle est stationnaire, on peut recalculer le corrélogramme de la série différenciée. L’exemple complet est répertorié ci-dessous.
from random import seed
from random import random
from matplotlib import pyplot
from pandas.plotting import autocorrelation_plot
# create random walk
seed(1)
random_walk = list()
random_walk.append(-1 if random() < 0.5 else 1)
for i in range(1, 1000):
movement = -1 if random() < 0.5 else 1
value = random_walk[i-1] + movement
random_walk.append(value)
# take difference
diff = list()
for i in range(1, len(random_walk)):
value = random_walk[i] - random_walk[i - 1]
diff.append(value)
# line plot
autocorrelation_plot(diff)
pyplot.show()
En exécutant l'exemple, nous ne pouvons voir aucune relation significative entre les observations décalées, comme on pourrait s'y attendre d'après la manière dont la marche aléatoire a été générée.
Toutes les corrélations sont faibles, proches de zéro et inférieures aux niveaux de confiance de 95 % et 99 % (au-delà de quelques hasards statistiques).
Prédire une marche aléatoire
Une marche aléatoire est imprévisible ; cela ne peut pas être raisonnablement prédit.
Compte tenu de la façon dont la marche aléatoire est construite, nous pouvons nous attendre à ce que la meilleure prédiction que nous puissions faire serait d'utiliser l'observation au pas de temps précédent comme ce qui se passera au pas de temps suivant.
Tout simplement parce que nous savons que le prochain pas de temps sera fonction du pas de temps précédent.
C’est ce qu’on appelle souvent la prévision naïve ou le modèle de persistance.
Nous pouvons implémenter cela en Python en divisant d'abord l'ensemble de données en ensembles d'entraînement et de test, puis en utilisant le modèle de persistance pour prédire le résultat à l'aide d'une méthode de prévision glissante. Une fois que toutes les prédictions sont collectées pour l’ensemble de test, l’erreur quadratique moyenne est calculée.
from random import seed
from random import random
from sklearn.metrics import mean_squared_error
# generate the random walk
seed(1)
random_walk = list()
random_walk.append(-1 if random() < 0.5 else 1)
for i in range(1, 1000):
movement = -1 if random() < 0.5 else 1
value = random_walk[i-1] + movement
random_walk.append(value)
# prepare dataset
train_size = int(len(random_walk) * 0.66)
train, test = random_walk[0:train_size], random_walk[train_size:]
# persistence
predictions = list()
history = train[-1]
for i in range(len(test)):
yhat = history
predictions.append(yhat)
history = test[i]
error = mean_squared_error(test, predictions)
print('Persistence MSE: %.3f' % error)
L’exécution de l’exemple estime l’erreur quadratique moyenne du modèle à 1.
Cela aussi est attendu, étant donné que nous savons que la variation d'un pas de temps au suivant sera toujours de 1, que ce soit dans le sens positif ou négatif, et que le carré de cette erreur attendue est 1 (1^2=1) .
Persistence MSE: 1.000
Une autre erreur que commettent les débutants en marche aléatoire est de supposer que si la plage d’erreur (variance) est connue, nous pouvons alors faire des prédictions en utilisant un processus de type génération de marche aléatoire.
Autrement dit, si nous savons que l'erreur est de -1 ou 1, alors pourquoi ne pas faire des prédictions en ajoutant un -1 ou 1 sélectionné au hasard à la valeur précédente.
Nous pouvons démontrer cette méthode de prédiction aléatoire en Python ci-dessous.
from random import seed
from random import random
from sklearn.metrics import mean_squared_error
# generate the random walk
seed(1)
random_walk = list()
random_walk.append(-1 if random() < 0.5 else 1)
for i in range(1, 1000):
movement = -1 if random() < 0.5 else 1
value = random_walk[i-1] + movement
random_walk.append(value)
# prepare dataset
train_size = int(len(random_walk) * 0.66)
train, test = random_walk[0:train_size], random_walk[train_size:]
# random prediction
predictions = list()
history = train[-1]
for i in range(len(test)):
yhat = history + (-1 if random() < 0.5 else 1)
predictions.append(yhat)
history = test[i]
error = mean_squared_error(test, predictions)
print('Random MSE: %.3f' % error)
En exécutant l’exemple, nous pouvons voir qu’en effet l’algorithme aboutit à de moins bonnes performances que la méthode de persistance, avec une erreur quadratique moyenne de 1,765.
Random MSE: 1.765
La persistance, ou la prévision naïve, est la meilleure prédiction que nous puissions faire pour une série chronologique de marche aléatoire.
Votre série chronologique est-elle une marche aléatoire ?
Votre série chronologique peut être une marche aléatoire.
Voici quelques façons de vérifier si votre série chronologique est une marche aléatoire :
- La série chronologique montre une forte dépendance temporelle qui décroît linéairement ou selon un schéma similaire.
- La série chronologique n'est pas stationnaire et la rendre stationnaire ne montre aucune structure manifestement apprenable dans les données.
- Le modèle de persistance constitue la meilleure source de prédictions fiables.
Ce dernier point est essentiel pour la prévision des séries chronologiques. Les prévisions de base avec le modèle de persistance déterminent rapidement si vous pouvez faire beaucoup mieux. Si vous n’y parvenez pas, vous travaillez probablement avec une marche aléatoire.
De nombreuses séries chronologiques sont des évolutions aléatoires, en particulier celles des prix des titres au fil du temps.
L’hypothèse de la marche aléatoire est une théorie selon laquelle les cours boursiers suivent une marche aléatoire et ne peuvent être prédits.
Une marche aléatoire est une marche dans laquelle les étapes ou directions futures ne peuvent être prédites sur la base de l’histoire passée. Lorsque le terme est appliqué au marché boursier, cela signifie que les variations à court terme des cours des actions sont imprévisibles.
— Page 26, Une promenade aléatoire à Wall Street : la stratégie éprouvée pour un investissement réussi
L’esprit humain voit des modèles partout et nous devons veiller à ne pas nous tromper et à perdre du temps en développant des modèles élaborés pour les processus de marche aléatoire.
Lectures complémentaires
Vous trouverez ci-dessous quelques ressources supplémentaires si vous souhaitez approfondir les promenades aléatoires.
- Une promenade aléatoire à Wall Street : la stratégie éprouvée pour un investissement réussi
- La marche de l’ivrogne : comment le hasard régit nos vies
- Section 7.3 Évaluation de la prévisibilité, prévision pratique de séries chronologiques avec R : un guide pratique
- Section 4.3 Marches aléatoires, séries chronologiques d'introduction avec R.
- Marche aléatoire sur Wikipédia
- Modèle de marche aléatoire par Robert F. Nau
Résumé
Dans ce tutoriel, vous avez découvert comment explorer la marche aléatoire avec Python.
Concrètement, vous avez appris :
- Comment créer un processus de marche aléatoire en Python.
- Comment explorer l'autocorrélation et la structure non stationnaire d'une marche aléatoire.
- Comment faire des prédictions pour une série chronologique de marche aléatoire.
Vous avez des questions sur les balades aléatoires, ou sur ce tutoriel ?
Posez vos questions dans les commentaires ci-dessous.