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のように次の投稿で比較評価をする。