Je veux faire des prévisions à un pas pour les séries chronologiques avec LSTM. Pour comprendre l'algorithme, je me suis construit un exemple de jouet: un simple processus autocorrélé.
def my_process(n, p, drift=0, displacement=0):
x = np.zeros(n)
for i in range(1, n):
x[i] = drift * i + p * x[i-1] + (1-p) * np.random.randn()
return x + displacement
J'ai ensuite construit un modèle LSTM dans Keras, en suivant cet exemple . J'ai simulé des processus avec une autocorrélation élevée p=0.99
de la longueur n=10000
, formé le réseau neuronal sur les 80 premiers% de celui-ci et l'ai laissé faire des prévisions à un pas pour les 20% restants.
Si je mets drift=0, displacement=0
, tout fonctionne bien:
Puis je me suis mis drift=0, displacement=10
et les choses ont pris la forme d'une poire (remarquez l'échelle différente sur l'axe des y):
Ce n'est pas très surprenant: les LSTM devraient être alimentés avec des données normalisées! J'ai donc normalisé les données en les redimensionnant à l'intervalle . Ouf, les choses vont bien à nouveau:
Ensuite, j'ai défini drift=0.00001, displacement=10
, normalisé à nouveau les données et exécuté l'algorithme dessus. Cela ne semble pas bon:
Apparemment, le LSTM ne peut pas faire face à une dérive. Que faire? (Oui, dans cet exemple de jouet, je pourrais simplement soustraire la dérive; mais pour les séries temporelles réelles, c'est beaucoup plus difficile). Je pourrais peut-être exécuter mon LSTM sur la différence au lieu de la série temporelle d'origine . Cela supprimera toute dérive constante de la série chronologique. Mais l'exécution du LSTM sur les séries chronologiques différenciées ne fonctionne pas du tout:
Ma question: pourquoi mon algorithme tombe-t-il en panne lorsque je l'utilise sur les séries chronologiques différenciées? Quelle est la bonne façon de gérer les dérives dans les séries chronologiques?
Voici le code complet de mon modèle:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
from keras.layers.core import Dense, Activation, Dropout
from keras.layers.recurrent import LSTM
from keras.models import Sequential
# The LSTM model
my_model = Sequential()
my_model.add(LSTM(input_shape=(1, 1), units=50, return_sequences=True))
my_model.add(Dropout(0.2))
my_model.add(LSTM(units=100, return_sequences=False))
my_model.add(Dropout(0.2))
my_model.add(Dense(units=1))
my_model.add(Activation('linear'))
my_model.compile(loss='mse', optimizer='rmsprop')
def my_prediction(x, model, normalize=False, difference=False):
# Plot the process x
plt.figure(figsize=(15, 7))
plt.subplot(121)
plt.plot(x)
plt.title('Original data')
n = len(x)
thrs = int(0.8 * n) # Train-test split
# Save starting values for test set to reverse differencing
x_test_0 = x[thrs + 1]
# Save minimum and maximum on test set to reverse normalization
x_min = min(x[:thrs])
x_max = max(x[:thrs])
if difference:
x = np.diff(x) # Take difference to remove drift
if normalize:
x = (2*x - x_min - x_max) / (x_max - x_min) # Normalize to [-1, 1]
# Split into train and test set. The model will be trained on one-step-ahead predictions.
x_train, y_train, x_test, y_test = x[0:(thrs-1)], x[1:thrs], x[thrs:(n-1)], x[(thrs+1):n]
x_train, x_test = x_train.reshape(-1, 1, 1), x_test.reshape(-1, 1, 1)
y_train, y_test = y_train.reshape(-1, 1), y_test.reshape(-1, 1)
# Fit the model
model.fit(x_train, y_train, batch_size=200, epochs=10, validation_split=0.05, verbose=0)
# Predict the test set
y_pred = model.predict(x_test)
# Reverse differencing and normalization
if normalize:
y_pred = ((x_max - x_min) * y_pred + x_max + x_min) / 2
y_test = ((x_max - x_min) * y_test + x_max + x_min) / 2
if difference:
y_pred = x_test_0 + np.cumsum(y_pred)
y_test = x_test_0 + np.cumsum(y_test)
# Plot estimation
plt.subplot(122)
plt.plot(y_pred[-100:], label='One-step-ahead-predictions')
plt.plot(y_test[-100:], label='Actual data')
plt.title('Prediction on test set')
plt.legend()
plt.show()
# Make plots
x = my_process(10000, 0.99, drift=0, displacement=0)
my_prediction(x, my_model, normalize=False, difference=False)
x = my_process(10000, 0.99, drift=0, displacement=10)
my_prediction(x, my_model, normalize=False, difference=False)
x = my_process(10000, 0.99, drift=0, displacement=10)
my_prediction(x, my_model, normalize=True, difference=False)
x = my_process(10000, 0.99, drift=0.00001, displacement=10)
my_prediction(x, my_model, normalize=True, difference=False)
x = my_process(10000, 0.99, drift=0.00001, displacement=10)
my_prediction(x, my_model, normalize=True, difference=True)
displacement
paramètre: . De plus, le dernier exemple utilise la normalisation ( après la différenciation), donc cela ne devrait pas être un problème ...