1. LSTMの簡単な説明
2.データの前処理
3.モデルの構築
4.モデルの評価
1. LSTMの簡単な説明
LSTMはニューラルネットワークの一種で、従来の音声、文章など連続的データ(Sequence)を扱うためのRNNのアルゴリズムを元にしている。しかし、RNNはSequenceの長さが長くなると、多少離れたデータの情報が消えるという短所がある。これを補完するために出てきたアルゴリズムがLSTMある。ディープラーニングをベースにしており、前述したARIMAやprophetより複雑なパターンを見つけることは可能である。
詳細については、多くのサイトで詳細な説明をしているので、その一つのサイトのリンクを残す。
https://qiita.com/KojiOhki/items/89cd7b69a8a6239d67ca
2.データの前処理
sklearnのtrain_test_splitの関数でtrainとtestセットに分離しよう。
from sklearn.model_selection import train_test_split
train, test = train_test_split(gold_price_series, train_size = 0.8, shuffle=False)
2016年3月までを学習データとしてモデルを学習し2016年3月から2020年4月までのデータでモデルを検証してみる。
学習の高速化のためにsklearnのMinMaxScalerを使用して0〜1でデータのサイズを合わせる。
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaler.fit(train)
train_trans = scaler.transform(train)
test_trans = scaler.transform(test)
pd.DataFrame(train_trans, index=train.index, columns=train.columns)
下のコードで一定の期間のデータ(本投稿の例示には、20日間をinput単位とする)を説明変数(x)に置き、その翌日を従属変数(y)に置くようにする。
def step_split(sequence, n_steps, n_features, n_predict_steps, test_set=False):
sequence = np.array(data).reshape(-1, n_features)
X, y = list(), list()
if test_set:
start_n = len(sequence) % n_steps
finish_n = len(sequence) - n_steps + 1
for i in range(start_n, finish_n):
seq_x = sequence[i:i+n_steps]
X.append(seq_x)
X = np.array(X)
X = X.reshape(X.shape[0], n_steps, n_features)
else:
start_n = (len(sequence) + n_predict_steps) % n_steps
finish_n = len(sequence) - n_predict_steps - n_steps + 1
for i in range(start_n, finish_n):
seq_x, seq_y = sequence[i:i+n_steps], sequence[i+n_steps:i+n_steps+n_predict_steps][:,0]
X.append(seq_x)
y.append(seq_y)
X = np.array(X)
y = np.array(y)
X = X.reshape(X.shape[0], n_steps, n_features)
y = y.reshape(y.shape[0], n_predict_steps)
return X, y
n_stepsでinputデータの期間の長さを定める。複数の説明変数を使用したい場合は、n_featuresを調整して、一日だけではなく複数の日付を予測したいときにはn_predict_stepsを調整すればよい。本例では、説明変数の1つ、翌日1日を予測するようにする。
n_steps = 20
n_features = 1
n_predict_steps = 1
x_train, y_train = step_split(train_trans, n_steps,n_features, n_predict_steps)
x_test, y_test = step_split(test_trans, n_steps,n_features, n_predict_steps)
pd.DataFrame(train_trans, index=train.index, columns=train.columns)
変換された最終的な学習データは、下記の通りである。 1つの列が一つのinputデータとなる。
pd.DataFrame(x_train.reshape(x_train.shape[1],x_train.shape[0]),
index = [f'day{x+1}' for x in range(x_train.shape[1])],
columns = [f'input_{x+1}' for x in range(x_train.shape[0])])
3.モデルの構築
必要なpackageを呼び出す。
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, LSTM, Bidirectional, Dropout
from tensorflow.keras.preprocessing.sequence import pad_sequences
16層のLSTMを作り、最後には1つの数字を予測するので、Dense(1)層を入れて、最も単純なLSTMを作った。
def create_model(stateful,batch_size, n_steps, n_features):
model = Sequential()
model.add(LSTM(16,
batch_input_shape=(batch_size, n_steps, n_features),
stateful=stateful
))
model.add(Dense(1))
model.compile(loss='mse', optimizer='adam')
return model
batch_size = 1
epochs = 11
x, y = step_split(scaler.transform(gold_price_series), n_steps, n_features, n_predict_steps)
y = scaler.inverse_transform(y)
model_stateful = create_model(True, batch_size, n_steps, n_features)
for i in range(epochs):
print('Epoch', i + 1, '/', epochs)
model_stateful.fit(x_train, y_train,
batch_size=batch_size,
epochs=1,
verbose=1,
shuffle=False,
validation_data=(x_test, y_test)
)
if i % 5 == 0:
y_hat = model_stateful.predict(x, batch_size=batch_size)
y_hat = scaler.inverse_transform(y_hat)
plt.figure(figsize=(25, 10))
plt.plot(gold_price_series.index[:len(y_hat)],y[:len(y_hat)])
plt.plot(gold_price_series.index[:len(y_hat)],y_hat)
plt.show()
1epoch後のFitting様子
6epochs後のFitting様子
11epochs後のFitting様子
4.モデルの評価
以前投稿のARIMA、Propehtのように次の投稿で比較評価をする。