TIME SERIES ANALYSIS

Predicting the Price of Bitcoin, Intro to LSTM

Use artificial intelligence to predict the value of Bitcoin

Introductory concepts

What is an RNN?

A recurrent neural network (RNN) is a class of artificial neural networks where connections between the nodes form a directed graph along a temporal sequence. This allows it to exhibit temporal dynamic behavior and makes them great for time series analysis, speech recognition, grammar learning, literal compositions, etc.

What is an LSTM?

Long-Short Term Memory (LSTM) is a type of RNN that allows us to process not only single data points (such as images) but also entire sequences of data (such as speech or video). They are a great choice for time series forecasting, and they are the type of architecture we will be using today.

LSTM Cell

Data Exploration

Before we do anything we need to gather the data (which I already did for you) and we need to understand the data. Let’s first load the dataset with Python and take a first look:

data = pd.read_csv("data/bitcoin.csv")
data = data.sort_values('Date')
data.head()
Bitcoin Data, source: coinbase
price = data[['Close']]

plt.figure(figsize = (15,9))
plt.plot(price)
plt.xticks(range(0, data.shape[0],50), data['Date'].loc[::50],rotation=45)
plt.title("Bitcoin Price",fontsize=18, fontweight='bold')
plt.xlabel('Date',fontsize=18)
plt.ylabel('Close Price (USD)',fontsize=18)
plt.show()
Price of Bitcoin from Dec, 2014 to Jun 2020
price.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 2001 entries, 2000 to 0
Data columns (total 1 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Close 2001 non-null float64
dtypes: float64(1)
memory usage: 31.3 KB

Data Preparation

Normalization

The first step we will take to our data is to normalize its values. The goal of normalization is to change the values of numeric columns in the data set to a common scale, without distorting differences in the ranges of values.

from sklearn.preprocessing import MinMaxScaler
min_max_scaler = MinMaxScaler()

norm_data = min_max_scaler.fit_transform(price.values)
Real: [370.], Normalized: [0.01280082]
Real: [426.1], Normalized: [0.01567332]
Real: [8259.99], Normalized: [0.41679416]

Data Split

During this step we are going to actually tackle 2 problems, the first is that we need to split our data set into training data and test data. Training data we will use to teach our model while the test data we will use as a baseline for comparison for our predictions. This is very important, as we want to make sure our predictions make sense, but we can’t test on the same data we train our network as we can run into the risk of overfitting.

def univariate_data(dataset, start_index, end_index, history_size, target_size):
data = []
labels = []

start_index = start_index + history_size
if end_index is None:
end_index = len(dataset) - target_size

for i in range(start_index, end_index):
indices = range(i-history_size, i)
# Reshape data from (history_size,) to (history_size, 1)
data.append(np.reshape(dataset[indices], (history_size, 1)))
labels.append(dataset[i+target_size])
return np.array(data), np.array(labels)
past_history = 5
future_target = 0

TRAIN_SPLIT = int(len(norm_data) * 0.8)


x_train, y_train = univariate_data(norm_data,
0,
TRAIN_SPLIT,
past_history,
future_target)

x_test, y_test = univariate_data(norm_data,
TRAIN_SPLIT,
None,
past_history,
future_target)

Build the model

The next step is to build our model architecture. Finding the right model is an art, and it will take several tries plus experience to find the right layers and hyper-parameters for each one of them.

from keras.models import Sequential
from keras.optimizers import Adam
from keras.layers import Dense, LSTM, LeakyReLU, Dropout

num_units = 64
learning_rate = 0.0001
activation_function = 'sigmoid'
adam = Adam(lr=learning_rate)
loss_function = 'mse'
batch_size = 5
num_epochs = 50

# Initialize the RNN
model = Sequential()
model.add(LSTM(units = num_units, activation=activation_function, input_shape=(None, 1)))
model.add(LeakyReLU(alpha=0.5))
model.add(Dropout(0.1))
model.add(Dense(units = 1))

# Compiling the RNN
model.compile(optimizer=adam, loss=loss_function)
Model: "sequential_13"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm_6 (LSTM) (None, 64) 16896
_________________________________________________________________
leaky_re_lu_4 (LeakyReLU) (None, 64) 0
_________________________________________________________________
dropout_4 (Dropout) (None, 64) 0
_________________________________________________________________
dense_6 (Dense) (None, 1) 65
=================================================================
Total params: 16,961
Trainable params: 16,961
Non-trainable params: 0
_________________________________________________________________

Train the model

Now that we have our data ready, and our model compiled, we can start training, and with Keras is as simple as one line of code:

# Using the training set to train the model
history = model.fit(
x_train,
y_train,
validation_split=0.1,
batch_size=batch_size,
epochs=num_epochs,
shuffle=False
)
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(loss))

plt.figure()

plt.plot(epochs, loss, 'b', label='Training loss')
plt.plot(epochs, val_loss, 'r', label='Validation loss')
plt.title("Training and Validation Loss")
plt.legend()

plt.show()
Training and Validation Loss

Prediction

With our model now trained, we can start making some predictions and evaluating those predictions to our test data to see how well our model is doing:

original = pd.DataFrame(min_max_scaler.inverse_transform(y_test))
predictions = pd.DataFrame(min_max_scaler.inverse_transform(model.predict(x_test)))

ax = sns.lineplot(x=original.index, y=original[0], label="Test Data", color='royalblue')
ax = sns.lineplot(x=predictions.index, y=predictions[0], label="Prediction", color='tomato')
ax.set_title('Bitcoin price', size = 14, fontweight='bold')
ax.set_xlabel("Days", size = 14)
ax.set_ylabel("Cost (USD)", size = 14)
ax.set_xticklabels('', size=10)
Predicted vs Actual Bitcoin price

Conclusion

RNNs and LSTM are great architectures we can use to analyze and predict time-series information. In this post, we focused more on the story than the technical details of the implementation, but if you are interested in the topic, do your research, check out the code, play with it, change the layers, the hyper-parameters, try different things, use different columns, or normalization methods, read more detailed articles, and papers on the subject.

I’m an entrepreneur, developer, author, speaker, and doer of things. I write about JavaScript, Python, AI, and programming in general.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store