Voorspelling van de volgende toekomstige waarde met behulp van Deep Learning en LSTM
De toekomst voorspellen met Deep Learning is een hot topic. Daarom wil ik me dit eigen maken.
Veel problemen zijn tijdgerelateerd. We hebben een aantal steekproeven verzameld en willen die nu gebruiken om de volgende waarde te voorspellen. Dat is waar deze post over gaat. Het gaat niet over het voorspellen van veel toekomstige waarden, dat is een ander onderwerp.
Als data scientist noob, werk ik gewoon door wat voorbeelden die ik op het internet heb gevonden. Ik verander de invoerreeks en kijk wat er gebeurt. Misschien vind je dit nuttig. Ik vond de 'Machine Learning Mastery' website erg nuttig. Ik zal vooral verwijzen naar het volgende artikel: 'How to Develop LSTM Models for Time Series Forecasting', zie onderstaande links.
LSTM (Lange-korte-termijngeheugen)
LSTM wordt gebruikt wanneer wij voorspellingen willen doen die op de tijd zijn gebaseerd. U hebt een dataset met steekproeven. Een steekproef kan een waarde zijn zoals de prijs van een aandeel, maar het kan ook de prijs van een aandeel zijn samen met andere waarden zoals het sentiment van een sociaal netwerk. Dit is totaal verschillend van het voorspellen van een waarde op basis van niet tijdgerelateerde waarden zoals in mijn vorige post 'Predicting values using Deep Learning and Keras'.
Bij LSTM kunnen we de tijdcomponent opnemen, maar dat is niet nodig. Bij LSTM gaat het om het definiëren van een opeenvolging in de tijd, niet om de tijd zelf.
Univariate vs. Multivariate
Er zijn twee basistypen LSTM.
Univariate Tijdreeksen:
- eendimensionaal
Voorbeeld1: Gebruik alleen de slotkoers van de aandelenmarkt
Voorbeeld2: Gebruik alleen het energieverbruik
Multivariate Tijdreeks:
- multidimensionaal
Voorbeeld1: gebruik de slotkoers van de beurs en bijv. de openingskoers en het sentiment van de sociale media
Voorbeeld2: gebruik het energieverbruik en de temperatuur
Hieronder zal ik zowel Univariate LSTM als Multivariate LSTM onderzoeken aan de hand van voorbeelden. Voor mij was het moeilijkste deel hoe de gegevens voor het model voor te bereiden. Toen ik dit eenmaal begreep, kon ik me eindelijk op de oplossing concentreren.
Univariate Tijdreeks: helling, gebruik alleen y
Ik werkte door het Univariate - Vanilla LSTM voorbeeld op de pagina 'How to Develop LSTM Models for Time Series Forecasting', zie links hieronder, en creëerde mijn eigen voorbeeld door de invoerreeks te veranderen met behulp van een functie:
# define input sequence
def fx(x):
y = 4 + 3*x
return y
x_end = 6
raw_seq = []
for x in range(0, x_end):
y = fx(x)
raw_seq.append(y)
Bereid de invoergegevens voor. We gebruiken de bovenstaande functie om enkele steekproeven te genereren:
raw_seq = [4, 7, 10, 13, 16, 19]
Kies het aantal tijdstappen:
n_steps = 3
Dan zetten we dit om in inputs en outputs zoals dit:
[ 4, 7, 10] -> 13
[ 7, 10, 13] -> 16
[10, 13, 16] -> 19
Om de volgende waarde te voorspellen gebruiken we de laatste inputs:
[13, 16, 19] -> ?
De inputs en outputs worden omgezet in:
X = [
[ 4 7 10]
[ 7 10 13]
[10 13 16]
]
y = [13 16 19]
En X wordt omgevormd tot:
reshaped X = [
[ [ 4] [ 7] [10] ]
[ [ 7] [10] [13] ]
[ [10] [13] [16] ]
]
Merk op dat we hier alleen de volgende waarde voorspellen. De code:
# Based on the Univariate Vanilla LSTM example from this page:
# How to Develop LSTM Models for Time Series Forecasting
# https://machinelearningmastery.com/how-to-develop-lstm-models-for-time-series-forecasting
#
# input sequence is a slope:
# - y = 4 + 3*x
# - we are using only y
#
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, LSTM
# split a univariate sequence into samples
def split_sequence(sequence, n_steps):
X, y = list(), list()
for i in range(len(sequence)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the sequence
if end_ix > len(sequence)-1:
break
# gather input and output parts of the pattern
seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
X.append(seq_x)
y.append(seq_y)
return np.array(X), np.array(y)
# choose a number of time steps
n_steps = 3
# define input sequence
def fx(x):
y = 4 + 3*x
return y
x_end = 6
raw_seq = []
for x in range(0, x_end):
y = fx(x)
raw_seq.append(y)
print('raw_seq = {}'.format(raw_seq))
# predict data
x_input = raw_seq[-1*n_steps:]
print('x_input = {}'.format(x_input))
y_expected = fx(x_end)
print('y_expected = {}'.format(y_expected))
# split into samples
X, y = split_sequence(raw_seq, n_steps)
print('X = {}'.format(X))
print('y = {}'.format(y))
# reshape from [samples, timesteps] into [samples, timesteps, features]
n_features = 1
print('X.shape[0] = {}'.format(X.shape[0]))
print('X.shape[1] = {}'.format(X.shape[1]))
X = X.reshape((X.shape[0], X.shape[1], n_features))
print('reshaped X = {}'.format(X))
# define model
def get_model(m):
if m == 'Vanilla_LSTM':
model = Sequential(name=m)
model.add(LSTM(50, activation='relu', input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
elif m == 'Stacked_LSTM':
model = Sequential(name=m)
model.add(LSTM(50, activation='relu', return_sequences=True, input_shape=(n_steps, n_features)))
model.add(LSTM(50, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
model.summary()
return model
#model = get_model('Vanilla_LSTM')
model = get_model('Stacked_LSTM')
# fit model
model.fit(X, y, epochs=200, verbose=0)
# show prediction
x_input = np.array(x_input)
x_input = x_input.reshape((1, n_steps, n_features))
yhat = model.predict(x_input, verbose=0)
print('prediction: for x_input = {}, yhat = {}, y_expected = {}'.format(x_input, yhat, y_expected))
En het resultaat:
raw_seq = [4, 7, 10, 13, 16, 19]
x_input = [13, 16, 19]
y_expected = 22
X = [[ 4 7 10]
[ 7 10 13]
[10 13 16]]
y = [13 16 19]
X.shape[0] = 3
X.shape[1] = 3
reshaped X = [[[ 4]
[ 7]
[10]]
[[ 7]
[10]
[13]]
[[10]
[13]
[16]]]
Model: "Stacked_LSTM"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm (LSTM) (None, 3, 50) 10400
lstm_1 (LSTM) (None, 50) 20200
dense (Dense) (None, 1) 51
=================================================================
Total params: 30,651
Trainable params: 30,651
Non-trainable params: 0
_________________________________________________________________
prediction: for x_input = [[[13]
[16]
[19]]], yhat = [[21.4401]], y_expected = 22
U kunt het proberen met Vanilla_LSTM en Stacked_LSTM modellen.
Multivariate Tijdreeksen: helling, gebruik X en y
Opnieuw heb ik het voorbeeld van Multivariate - Multiple Input Series op de pagina 'How to Develop LSTM Models for Time Series Forecasting', zie onderstaande links, doorgewerkt en mijn eigen voorbeeld gemaakt door de invoerreeks met behulp van een functie te wijzigen:
# define input sequence
def fx(x):
y = 4 + 3*x
return y
x_end = 6
in_seq = []
out_seq = []
for x in range(0, x_end):
y = fx(x)
in_seq.append(x)
out_seq.append(y)
in_seq = np.array(in_seq)
out_seq = np.array(out_seq)
Bereid de invoergegevens voor. We gebruiken de bovenstaande functie om enkele steekproeven te genereren:
in_seq = [0 1 2 3 4 5]
out_seq = [ 4 7 10 13 16 19]
Kies het aantal tijdstappen:
n_steps = 3
Dan zetten we dit om in inputs en outputs zoals dit:
[ [0] [1] [2] ] -> 10
[ [1] [2] [3] ] -> 13
[ [2] [3] [4] ] -> 16
[ [3] [4] [5] ] -> 19
Om de volgende waarde te voorspellen gebruiken we de laatste inputs:
[ [ 4] [ 5] [ 6] ] -> ?
De inputs en outputs worden omgezet in:
X = [
[ [0] [1] [2] ]
[ [1] [2] [3] ]
[ [2] [3] [4] ]
[ [3] [4] [5] ]
]
y = [10 13 16 19]
Merk op dat we hier alleen de volgende waarde voorspellen. De code:
# Based on the multivariate LSTM Multiple Input Series example from this page:
# How to Develop LSTM Models for Time Series Forecasting
# https://machinelearningmastery.com/how-to-develop-lstm-models-for-time-series-forecasting
#
# input sequence is a slope:
# - y = 4 + 3*x
# - we are using both x and y
#
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, LSTM
# split a multivariate sequence into samples
def split_sequences(sequences, n_steps):
X, y = list(), list()
for i in range(len(sequences)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the dataset
if end_ix > len(sequences):
break
# gather input and output parts of the pattern
seq_x, seq_y = sequences[i:end_ix, :-1], sequences[end_ix-1, -1]
X.append(seq_x)
y.append(seq_y)
return np.array(X), np.array(y)
# choose a number of time steps
n_steps = 4
# define input sequence
def fx(x):
y = 4 + 3*x
return y
x_end = 12
in_seq = []
out_seq = []
for x in range(0, x_end):
y = fx(x)
in_seq.append(x)
out_seq.append(y)
in_seq = np.array(in_seq)
out_seq = np.array(out_seq)
print('in_seq = {}'.format(in_seq))
print('out_seq = {}'.format(out_seq))
# convert to [rows, columns] structure
in_seq = in_seq.reshape((len(in_seq), 1))
out_seq = out_seq.reshape((len(out_seq), 1))
print('after convert to [rows, columns]:')
print('in_seq = {}'.format(in_seq))
print('out_seq = {}'.format(out_seq))
# horizontally stack columns
dataset = np.hstack((in_seq, out_seq))
print('dataset = {}'.format(dataset))
# convert into input/output
X, y = split_sequences(dataset, n_steps)
print('X = {}'.format(X))
print('y = {}'.format(y))
# prediction data = last row of dataset
x_input = X[-1]
y_expected = y[-1]
# remove prediction data from dataset
X = X[:-1]
y = y[:-1]
print('X = {}'.format(X))
print('y = {}'.format(y))
# the dataset knows the number of features, e.g. 2
n_features = X.shape[2]
print('n_features = {}'.format(n_features))
# define model
def get_model(m):
if m == 'Vanilla_LSTM':
model = Sequential(name=m)
model.add(LSTM(50, activation='relu', input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
elif m == 'Stacked_LSTM':
model = Sequential(name=m)
model.add(LSTM(50, activation='relu', return_sequences=True, input_shape=(n_steps, n_features)))
model.add(LSTM(50, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
model.summary()
return model
model = get_model('Vanilla_LSTM')
#model = get_model('Stacked_LSTM')
# fit model
model.fit(X, y, epochs=200, verbose=0)
# show prediction
x_input = x_input.reshape((1, n_steps, n_features))
yhat = model.predict(x_input, verbose=0)
print('prediction: for x_input = {}, yhat = {}, y_expected = {}'.format(x_input, yhat, y_expected))
En het resultaat:
in_seq = [ 0 1 2 3 4 5 6 7 8 9 10 11]
out_seq = [ 4 7 10 13 16 19 22 25 28 31 34 37]
after convert to [rows, columns]:
in_seq = [[ 0]
[ 1]
[ 2]
[ 3]
[ 4]
[ 5]
[ 6]
[ 7]
[ 8]
[ 9]
[10]
[11]]
out_seq = [[ 4]
[ 7]
[10]
[13]
[16]
[19]
[22]
[25]
[28]
[31]
[34]
[37]]
dataset = [[ 0 4]
[ 1 7]
[ 2 10]
[ 3 13]
[ 4 16]
[ 5 19]
[ 6 22]
[ 7 25]
[ 8 28]
[ 9 31]
[10 34]
[11 37]]
X = [[[ 0]
[ 1]
[ 2]
[ 3]]
[[ 1]
[ 2]
[ 3]
[ 4]]
[[ 2]
[ 3]
[ 4]
[ 5]]
[[ 3]
[ 4]
[ 5]
[ 6]]
[[ 4]
[ 5]
[ 6]
[ 7]]
[[ 5]
[ 6]
[ 7]
[ 8]]
[[ 6]
[ 7]
[ 8]
[ 9]]
[[ 7]
[ 8]
[ 9]
[10]]
[[ 8]
[ 9]
[10]
[11]]]
y = [13 16 19 22 25 28 31 34 37]
X = [[[ 0]
[ 1]
[ 2]
[ 3]]
[[ 1]
[ 2]
[ 3]
[ 4]]
[[ 2]
[ 3]
[ 4]
[ 5]]
[[ 3]
[ 4]
[ 5]
[ 6]]
[[ 4]
[ 5]
[ 6]
[ 7]]
[[ 5]
[ 6]
[ 7]
[ 8]]
[[ 6]
[ 7]
[ 8]
[ 9]]
[[ 7]
[ 8]
[ 9]
[10]]]
y = [13 16 19 22 25 28 31 34]
n_features = 1
Model: "Vanilla_LSTM"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm (LSTM) (None, 50) 10400
dense (Dense) (None, 1) 51
=================================================================
Total params: 10,451
Trainable params: 10,451
Non-trainable params: 0
_________________________________________________________________
prediction: for x_input = [[[ 8]
[ 9]
[10]
[11]]], yhat = [[35.79921]], y_expected = 37
U kunt het proberen met Vanilla_LSTM en Stacked_LSTM modellen.
Samenvatting
Dit was een totaal andere ervaring dan die beschreven in de vorige post 'Predicting values using Deep Learning and Keras'. Begrijpen hoe de gegevens moeten worden voorbereid was erg belangrijk, zo niet het belangrijkste. Maar er is hierover uitstekende documentatie op het internet te vinden.
LSMT is een black box, daar hou ik van. Maar het kan veel datapunten (monsters) nodig hebben. Het belangrijkste voor mij op dit moment is de kwaliteit van de voorspelling. Hoe goed is het? Ook kan ik de toekomst voorspellen voor de volgende tijdseenheid, maar ik wil ook de toekomst voorspellen voor veel meer tijdseenheden. Dat willen we toch allemaal? Heel veel nog te leren ...
Links / credits
How to Convert a Time Series to a Supervised Learning Problem in Python
https://machinelearningmastery.com/convert-time-series-supervised-learning-problem-python
How to Develop LSTM Models for Time Series Forecasting
https://machinelearningmastery.com/how-to-develop-lstm-models-for-time-series-forecasting
How to Use the TimeseriesGenerator for Time Series Forecasting in Keras
https://machinelearningmastery.com/how-to-use-the-timeseriesgenerator-for-time-series-forecasting-in-keras
Understand Keras's RNN behind the scenes with a sin wave example - Stateful and Stateless prediction
https://fairyonice.github.io/Understand-Keras's-RNN-behind-the-scenes-with-a-sin-wave-example.html
Lees meer
Deep Learning Machine Learning
Recent
- Database UUID primaire sleutels van je webapplicatie verbergen
- Don't Repeat Yourself (DRY) met Jinja2
- SQLAlchemy, PostgreSQL, maximum aantal rijen per user
- Toon de waarden in SQLAlchemy dynamische filters
- Veilige gegevensoverdracht met Public Key versleuteling en pyNaCl
- rqlite: een alternatief voor SQLite met hoge beschikbaarheid en distributed
Meest bekeken
- Met behulp van Python's pyOpenSSL om SSL-certificaten die van een host zijn gedownload te controleren
- Gebruik van UUIDs in plaats van Integer Autoincrement Primary Keys met SQLAlchemy en MariaDb
- Maak verbinding met een dienst op een Docker host vanaf een Docker container
- PyInstaller en Cython gebruiken om een Python executable te maken
- SQLAlchemy: Gebruik van Cascade Deletes om verwante objecten te verwijderen
- Flask RESTful API verzoekparametervalidatie met Marshmallow-schema's