Predicción del próximo valor futuro mediante Deep Learning y LSTM
Predecir el futuro con Deep Learning es un tema candente. Por eso quiero dominarlo.
Muchos problemas están relacionados con el tiempo. Hemos recogido algunas muestras y ahora queremos utilizarlas para predecir el siguiente valor. De eso trata este post. No se trata de predecir muchos valores futuros, eso es un tema diferente.
Como científico de datos novato, sólo trabajo con algunos ejemplos que encontré en Internet. Cambio la secuencia de entrada y veo lo que sucede. Puede que esto te resulte útil. He encontrado el sitio web 'Machine Learning Mastery' muy útil. Me referiré principalmente al siguiente artículo: 'How to Develop LSTM Models for Time Series Forecasting', ver enlaces más abajo.
LSTM (Memoria a corto plazo)
LSTM se utiliza cuando queremos hacer predicciones basadas en el tiempo. Se tiene un conjunto de datos con muestras. Una muestra puede ser un valor como el precio de una acción, pero también puede ser el precio de una acción junto con otros valores como el sentimiento de las redes sociales. Esto es totalmente diferente a la predicción de un valor basado en valores no relacionados con el tiempo como en mi anterior post 'Predicting values using Deep Learning and Keras'.
Con LSTM podemos incluir el componente temporal pero no es necesario. LSTM trata de definir una secuencia en el tiempo, no del tiempo en sí.
Univariate vs Multivariate
Hay dos tipos básicos de LSTM.
Series temporales Univariate :
- unidimensional
Ejemplo1: Utilizar sólo el precio de cierre de la bolsa
Ejemplo2: Utilizar sólo el consumo de energía
Multivariate Series temporales:
- multidimensional
Ejemplo1: utilizar el precio de cierre de la bolsa y, por ejemplo, el precio de apertura y el sentimiento de las redes sociales
Ejemplo2: utilizar el consumo de energía y la temperatura
A continuación voy a investigar tanto Univariate LSTM como Multivariate LSTM utilizando ejemplos. Para mí la parte más difícil fue cómo preparar los datos para el modelo. Una vez que entendí esto, finalmente pude centrarme en la solución.
Univariate Series temporales: pendiente, usar sólo y
Trabajé a través del ejemplo Univariate - Vanilla LSTM en la página 'Cómo desarrollar modelos LSTM para la previsión de series temporales', ver enlaces más abajo, y creé mi propio ejemplo cambiando la secuencia de entrada utilizando una función:
# 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)
Preparar los datos de entrada. Utilizamos la función anterior para generar algunas muestras:
raw_seq = [4, 7, 10, 13, 16, 19]
Elija el número de pasos de tiempo:
n_steps = 3
Luego transformamos esto en entradas y salidas así:
[ 4, 7, 10] -> 13
[ 7, 10, 13] -> 16
[10, 13, 16] -> 19
Para predecir el siguiente valor utilizamos las últimas entradas:
[13, 16, 19] -> ?
Las entradas y salidas se convierten en:
X = [
[ 4 7 10]
[ 7 10 13]
[10 13 16]
]
y = [13 16 19]
Y X se transforma en:
reshaped X = [
[ [ 4] [ 7] [10] ]
[ [ 7] [10] [13] ]
[ [10] [13] [16] ]
]
Nótese que aquí sólo predecimos el siguiente valor. El código:
# 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))
Y el resultado:
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
Puede probarlo con los modelos Vanilla_LSTM y Stacked_LSTM .
Multivariate Series temporales: pendiente, uso de X e y
Una vez más, he trabajado con el ejemplo Multivariate - Multiple Input Series en la página 'Cómo desarrollar modelos LSTM para la previsión de series temporales', ver enlaces más abajo, y he creado mi propio ejemplo cambiando la secuencia de entrada mediante una función:
# 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)
Preparar los datos de entrada. Utilizamos la función anterior para generar algunas muestras:
in_seq = [0 1 2 3 4 5]
out_seq = [ 4 7 10 13 16 19]
Elija el número de pasos de tiempo:
n_steps = 3
Luego transformamos esto en entradas y salidas así:
[ [0] [1] [2] ] -> 10
[ [1] [2] [3] ] -> 13
[ [2] [3] [4] ] -> 16
[ [3] [4] [5] ] -> 19
Para predecir el siguiente valor utilizamos las últimas entradas:
[ [ 4] [ 5] [ 6] ] -> ?
Las entradas y salidas se convierten en:
X = [
[ [0] [1] [2] ]
[ [1] [2] [3] ]
[ [2] [3] [4] ]
[ [3] [4] [5] ]
]
y = [10 13 16 19]
Obsérvese que aquí sólo predecimos el siguiente valor. El código:
# 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))
Y el resultado:
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
Puedes probarlo con los modelos Vanilla_LSTM y Stacked_LSTM .
Resumen
Esta fue una experiencia totalmente diferente a la descrita en el post anterior 'Predicting values using Deep Learning and Keras'. Entender cómo preparar los datos fue muy importante, si no lo más importante. Pero hay una excelente documentación en Internet sobre esto.
LSMT es una caja negra, esto me gusta. Pero puede necesitar muchos puntos de datos (muestras). Lo más importante para mí en este momento es la calidad de la predicción. También puedo predecir el futuro para la siguiente unidad de tiempo, pero también quiero predecir el futuro para muchas más unidades de tiempo. Todos queremos esto, ¿verdad? Todavía queda mucho por aprender...
Enlaces / créditos
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
Leer más
Deep Learning Machine Learning
Recientes
- Cómo ocultar las claves primarias de la base de datos UUID de su aplicación web
- Don't Repeat Yourself (DRY) con Jinja2
- SQLAlchemy, PostgreSQL, número máximo de filas por user
- Mostrar los valores en filtros dinámicos SQLAlchemy
- Transferencia de datos segura con cifrado de Public Key y pyNaCl
- rqlite: una alternativa de alta disponibilidad y dist distribuida SQLite
Más vistos
- Usando Python's pyOpenSSL para verificar los certificados SSL descargados de un host
- Usando UUIDs en lugar de Integer Autoincrement Primary Keys con SQLAlchemy y MariaDb
- Conectarse a un servicio en un host Docker desde un contenedor Docker
- Usando PyInstaller y Cython para crear un ejecutable de Python
- SQLAlchemy: Uso de Cascade Deletes para eliminar objetos relacionados
- Flask RESTful API validación de parámetros de solicitud con esquemas Marshmallow