来自数据帧的神经网络 LSTM 输入形状 [英] Neural Network LSTM input shape from dataframe
问题描述
我正在尝试使用 Keras 实现一个 LSTM.
我知道 Keras 中的 LSTM 需要一个形状为 (nb_samples, timesteps, input_dim)
的 3D 张量作为输入.但是,我不完全确定输入在我的情况下应该是什么样子,因为我对每个输入只有一个 T
观察样本,而不是多个样本,即 (nb_samples=1,时间步长=T,input_dim=N)
.将我的每个输入分成长度为 T/M
的样本是否更好?T
对我来说大约有几百万个观察值,那么在这种情况下每个样本应该多长时间,即我将如何选择 M
?
另外,这个张量应该看起来像:
[[[[a_11, a_12, ..., a_1M], [a_21, a_22, ..., a_2M], ..., [a_N1, a_N2, ..., a_NM]],[[b_11, b_12, ..., b_1M], [b_21, b_22, ..., b_2M], ..., [b_N1, b_N2, ..., b_NM]],...,[[x_11, x_12, ..., a_1M], [x_21, x_22, ..., x_2M], ..., [x_N1, x_N2, ..., x_NM]]]
其中 M 和 N 定义如前,x 对应于我从上面讨论的拆分中获得的最后一个样本?
最后,给定一个 Pandas 数据框,每列有 T
观察值,N
列,每个输入一个,我如何创建这样的输入以提供给 Keras?
以下是设置时间序列数据以训练 LSTM 的示例.模型输出是废话,因为我设置它只是为了演示如何构建模型.
将pandas导入为pd将 numpy 导入为 np# 获取一些时间序列数据df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/timeseries.csv")df.head()
时间序列数据帧:
日期 A B C D E F G0 2008-03-18 24.68 164.93 114.73 26.27 19.21 28.87 63.441 2008-03-19 24.18 164.89 114.75 26.22 19.07 27.76 59.982 2008-03-20 23.99 164.63 115.04 25.78 19.01 27.04 59.613 2008-03-25 24.14 163.92 114.85 27.41 19.61 27.84 59.414 2008-03-26 24.44 163.45 114.84 26.86 19.53 28.02 60.09
您可以将输入构建到向量中,然后使用 pandas .cumsum()
函数构建时间序列的序列:
# 把你的输入放到一个列表中df['single_input_vector'] = df[input_cols].apply(tuple,axis=1).apply(list)# 双重封装列表,以便您可以在下一步中对其进行求和,并将时间步作为单独的元素保存df['single_input_vector'] = df.single_input_vector.apply(lambda x: [list(x)])# 使用 .cumsum() 在当前行向量列表中包含前一行向量df['cumulative_input_vectors'] = df.single_input_vector.cumsum()
可以用类似的方式设置输出,但它将是单个向量而不是序列:
#如果你的输出是多维的,你需要在一个对象中捕获这些维度# 如果你的输出是单维的,这一步可能没有必要df['output_vector'] = df[output_cols].apply(tuple,axis=1).apply(list)
输入序列的长度必须相同才能通过模型运行它们,因此您需要将它们填充为累积向量的最大长度:
# 填充你的序列,使它们的长度相同从 keras.preprocessing.sequence 导入 pad_sequencesmax_sequence_length = df.cumulative_input_vectors.apply(len).max()# 保存为列表padded_sequences = pad_sequences(df.cumulative_input_vectors.tolist(), max_sequence_length).tolist()df['padded_input_vectors'] = pd.Series(padded_sequences).apply(np.asarray)
可以从数据框中提取训练数据并放入 numpy 数组中.请注意,来自数据帧的输入数据不会构成 3D 数组.它构成了一个数组数组,这不是一回事.
您可以使用 hstack 和 reshape 来构建 3D 输入数组.
# 提取你的训练数据X_train_init = np.asarray(df.padd_input_vectors)# 使用 hstack to 和 reshape 使输入成为 3d 向量X_train = np.hstack(X_train_init).reshape(len(df),max_sequence_length,len(input_cols))y_train = np.hstack(np.asarray(df.output_vector)).reshape(len(df),len(output_cols))
证明:
<预><代码>>>>打印(X_train_init.shape)(11,)>>>打印(X_train.shape)(11, 11, 6)>>>打印(X_train == X_train_init)错误的获得训练数据后,您可以定义输入层和输出层的维度.
# 获取你的输入尺寸# 输入长度是一个输入序列的长度(即样本的行数)# 输入dim是一个输入向量的维数(即输入列数)input_length = X_train.shape[1]input_dim = X_train.shape[2]# 输出维度是单个输出向量的形状# 在这种情况下它只是 1,但它可能更多output_dim = len(y_train[0])
构建模型:
from keras.models import Model, Sequential从 keras.layers 导入 LSTM,密集# 构建模型模型 = 顺序()# 我随意选择输出维度为 4model.add(LSTM(4, input_dim = input_dim, input_length = input_length))# 最大输出值为 >1 所以 relu 用作最终激活.model.add(Dense(output_dim, activation='relu'))model.compile(loss='mean_squared_error',优化器='sgd',指标=['准确度'])
最后您可以训练模型并将训练日志保存为历史记录:
# 将 batch_size 设置为 7 以表明它不必是您的样本大小的一个因子或倍数history = model.fit(X_train, y_train,batch_size=7,nb_epoch=3,详细 = 1)
输出:
纪元1/311/11 [==============================] - 0s - 损失:3498.5756 - acc:0.0000e+00时代2/311/11 [==============================] - 0s - 损失:3498.5755 - acc:0.0000e+00时代3/311/11 [==============================] - 0s - 损失:3498.5757 - acc:0.0000e+00
就是这样.使用 model.predict(X)
其中 X
与 X_train
的格式相同(样本数除外),以便从模型.
I am trying to implement an LSTM with Keras.
I know that LSTM's in Keras require a 3D tensor with shape (nb_samples, timesteps, input_dim)
as an input. However, I am not entirely sure how the input should look like in my case, as I have just one sample of T
observations for each input, not multiple samples, i.e. (nb_samples=1, timesteps=T, input_dim=N)
. Is it better to split each of my inputs into samples of length T/M
? T
is around a few million observations for me, so how long should each sample in that case be, i.e., how would I choose M
?
Also, am I right in that this tensor should look something like:
[[[a_11, a_12, ..., a_1M], [a_21, a_22, ..., a_2M], ..., [a_N1, a_N2, ..., a_NM]],
[[b_11, b_12, ..., b_1M], [b_21, b_22, ..., b_2M], ..., [b_N1, b_N2, ..., b_NM]],
...,
[[x_11, x_12, ..., a_1M], [x_21, x_22, ..., x_2M], ..., [x_N1, x_N2, ..., x_NM]]]
where M and N defined as before and x corresponds to the last sample that I would have obtained from splitting as discussed above?
Finally, given a pandas dataframe with T
observations in each column, and N
columns, one for each input, how can I create such an input to feed to Keras?
Below is an example that sets up time series data to train an LSTM. The model output is nonsense as I only set it up to demonstrate how to build the model.
import pandas as pd
import numpy as np
# Get some time series data
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/timeseries.csv")
df.head()
Time series dataframe:
Date A B C D E F G
0 2008-03-18 24.68 164.93 114.73 26.27 19.21 28.87 63.44
1 2008-03-19 24.18 164.89 114.75 26.22 19.07 27.76 59.98
2 2008-03-20 23.99 164.63 115.04 25.78 19.01 27.04 59.61
3 2008-03-25 24.14 163.92 114.85 27.41 19.61 27.84 59.41
4 2008-03-26 24.44 163.45 114.84 26.86 19.53 28.02 60.09
You can build put inputs into a vector and then use pandas .cumsum()
function to build the sequence for the time series:
# Put your inputs into a single list
df['single_input_vector'] = df[input_cols].apply(tuple, axis=1).apply(list)
# Double-encapsulate list so that you can sum it in the next step and keep time steps as separate elements
df['single_input_vector'] = df.single_input_vector.apply(lambda x: [list(x)])
# Use .cumsum() to include previous row vectors in the current row list of vectors
df['cumulative_input_vectors'] = df.single_input_vector.cumsum()
The output can be set up in a similar way, but it will be a single vector instead of a sequence:
# If your output is multi-dimensional, you need to capture those dimensions in one object
# If your output is a single dimension, this step may be unnecessary
df['output_vector'] = df[output_cols].apply(tuple, axis=1).apply(list)
The input sequences have to be the same length to run them through the model, so you need to pad them to be the max length of your cumulative vectors:
# Pad your sequences so they are the same length
from keras.preprocessing.sequence import pad_sequences
max_sequence_length = df.cumulative_input_vectors.apply(len).max()
# Save it as a list
padded_sequences = pad_sequences(df.cumulative_input_vectors.tolist(), max_sequence_length).tolist()
df['padded_input_vectors'] = pd.Series(padded_sequences).apply(np.asarray)
Training data can be pulled from the dataframe and put into numpy arrays. Note that the input data that comes out of the dataframe will not make a 3D array. It makes an array of arrays, which is not the same thing.
You can use hstack and reshape to build a 3D input array.
# Extract your training data
X_train_init = np.asarray(df.padded_input_vectors)
# Use hstack to and reshape to make the inputs a 3d vector
X_train = np.hstack(X_train_init).reshape(len(df),max_sequence_length,len(input_cols))
y_train = np.hstack(np.asarray(df.output_vector)).reshape(len(df),len(output_cols))
To prove it:
>>> print(X_train_init.shape)
(11,)
>>> print(X_train.shape)
(11, 11, 6)
>>> print(X_train == X_train_init)
False
Once you have training data you can define the dimensions of your input layer and output layers.
# Get your input dimensions
# Input length is the length for one input sequence (i.e. the number of rows for your sample)
# Input dim is the number of dimensions in one input vector (i.e. number of input columns)
input_length = X_train.shape[1]
input_dim = X_train.shape[2]
# Output dimensions is the shape of a single output vector
# In this case it's just 1, but it could be more
output_dim = len(y_train[0])
Build the model:
from keras.models import Model, Sequential
from keras.layers import LSTM, Dense
# Build the model
model = Sequential()
# I arbitrarily picked the output dimensions as 4
model.add(LSTM(4, input_dim = input_dim, input_length = input_length))
# The max output value is > 1 so relu is used as final activation.
model.add(Dense(output_dim, activation='relu'))
model.compile(loss='mean_squared_error',
optimizer='sgd',
metrics=['accuracy'])
Finally you can train the model and save the training log as history:
# Set batch_size to 7 to show that it doesn't have to be a factor or multiple of your sample size
history = model.fit(X_train, y_train,
batch_size=7, nb_epoch=3,
verbose = 1)
Output:
Epoch 1/3
11/11 [==============================] - 0s - loss: 3498.5756 - acc: 0.0000e+00
Epoch 2/3
11/11 [==============================] - 0s - loss: 3498.5755 - acc: 0.0000e+00
Epoch 3/3
11/11 [==============================] - 0s - loss: 3498.5757 - acc: 0.0000e+00
That's it. Use model.predict(X)
where X
is the same format (other than the number of samples) as X_train
in order to make predictions from the model.
这篇关于来自数据帧的神经网络 LSTM 输入形状的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!