How to split a data frame into time-series for LSTM deep neural network

In this article, I am going to show how to prepare a Pandas data frame to use it as an input for a recurrent neural network (for example, LSTM).

As an example, I am going to use a data set of Bitcoin prices. My goal is to train a neural network to use data from the current day + the past 29 days (so 30 days in total) to predict the BTC price during the next seven days.

In my input data frame, I have average daily prices indexed by date.

1
2
3
4
5
6
7
8
btc_prices.head()

#date
#2011-12-31    4.471603
#2012-01-01    4.806667
#2012-01-02    5.000000
#2012-01-03    5.252500
#2012-01-04    5.208159

Now, I am going to define a function which takes as arguments the data frame to be split, the number of days to be used as independent features (input), and the number of days which are the dependent features (target).

Prepare historical and future data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def build_training_data(dataset, history_size = 30, target_size = 7):
    start_index = history_size
    end_index = len(dataset) - target_size

    data = []
    labels = []

    for i in range(start_index, end_index):
        indices = range(i - history_size, i, 1)
        data.append(dataset[indices])
        labels.append(dataset[i:i + target_size])

    data = np.array(data)
    labels = np.array(labels)
    return data, labels

dataset = btc_prices.values
data, labels = build_training_data(dataset)

To show that the function works correctly, I pick a day (in this case, the 2000th day in the data frame) and plot both the data for that date and the labels.

1
2
3
4
5
6
7
8
9
10
11
12
13
plt.rcParams["figure.figsize"] = (20,10)

day = 2000
plt.plot(range(0, 30), data[day], 'k-', label = 'Historical data (today + last 29 days)')
plt.plot(range(29, 37), np.concatenate([data[day][29:], labels[day]]), 'g-', label = 'To be predicted (next 7 days)')
plt.axvline(x=29, c = 'r')
plt.plot(29, data[day][29], 'rx', markersize = 20, label = "Today")
plt.xticks(range(0, 37), range(-29, 7))
plt.title('Training data with labels')
plt.xlabel('Days')
plt.ylabel('BTC price in USD')
plt.legend()
plt.show()
Chart of historical data and labels
Chart of historical data and labels

The part that is not shown here

Remember to split the data into training, validation, and test data frame. Additionally, we must normalize all data (using the mean and standard deviation of the training set).

Preparing LSTM input

Before I can use it as the input for LSTM, I have to reshape the values. I have values of a single feature for 30 days, so the correct shape of the input data frame is (-1, 30, 1).

The label data frame contains seven values of a single feature, so its shape is (-1, 7, 1).

1
2
3
4
5
6
7
8
x_train = x_train.reshape((-1, 30, 1))
y_train = y_train.reshape((-1, 7))

x_validation = x_validation.reshape((-1, 30, 1))
y_validation = y_validation.reshape((-1, 7))

x_test = x_test.reshape((-1, 30, 1))
y_test = y_test.reshape((-1, 7))

Neural network

To configure the neural network correctly, we have to set (30, 1) as the shape of the input layer and use seven neurons in the output layer.

1
2
3
4
5
tf.keras.models.Sequential([
    tf.keras.layers.LSTM(24, input_shape=(30, 1), return_sequences = True),
    # put the rest of the layers here
    tf.keras.layers.Dense(7, activation='linear')
])

Remember to share on social media!
If you like this text, please share it on Facebook/Twitter/LinkedIn/Reddit or other social media.

If you watch programming live streams, check out my YouTube channel.
You can also follow me on Twitter: @mikulskibartosz

If you want to hire me, send me a message on LinkedIn or Twitter.


Bartosz Mikulski
Bartosz Mikulski * big data engineer * conference speaker * co-founder of Software Craftsmanship Poznan & Poznan Scala User Group