LSTMで株価予測入門 [Python,Keras]
こんにちは、スーパーソフトウエアの船木です。
時系列データの未来の値をディープラーニングで予測する方法を見ていきます。RNN(再帰型ニューラルネットワーク)の一種であるLSTMを使いますが、複雑な数式やロジックではなく実用性やメリットを感じてもらうために入門的な内容です。興味を持った人は、より詳しく数式や論文にあたってもらえればと思います。
また、当然ですが投資取引への勧誘等を目的にしたものではなく、本情報を利用した際の取引等は全て自己の責任において行ってください。
LSTMとは
LSTMとは「Long Short Term Memory」の略で、長・短期記憶と呼ばれるディープラーニングのアーキテクチャです。元々RNNは古いアウトプットを次のインプットとして使用することで学習していきますが、長期的な特徴の学習には向いていない仕組みでした。
LSTMのアプローチ方法
LSTMの準備
import numpy as np
from sklearn.metrics import r2_score
from pandas_datareader import data as pdr
import yfinance as yf
yf.pdr_override()
from datetime import datetime
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense, LSTM, Dropout
import matplotlib.pyplot as plt
plt.style.use("fivethirtyeight")
%matplotlib inline
Kerasやmatplotlibなど必要なライブラリを読み込みます。Kerasとは、Googleが開発したディープラーニングのフレームワークTensorflowに含まれているライブラリで、記述が比較的簡単になっています。また、yfinanceライブラリがyahooからデータ取得が出来ないようのでpdr_overrideでfixしています。
Google(アルファベット)のOHLCVを取得する
s_target = 'GOOG'
df = pdr.get_data_yahoo(s_target, start='2014-01-01', end=datetime.now())
df.head()
株価データをグラフで確認
plt.figure(figsize=(16,6))
plt.title(s_target + ' Close Price History')
plt.plot(df['Close'])
plt.xlabel('Date', fontsize=14)
plt.ylabel('Close Price USD ($)', fontsize=14)
plt.show()
株価のMA(移動平均)も確認
ma_day = [10, 20, 50]
for ma in ma_day:
column_name = f"MA for {ma} days"
df[column_name] = df['Adj Close'].rolling(ma).mean()
plt.figure(figsize=(16,6))
plt.title(s_target + ' Close Price MA History')
plt.plot(df['Close'][-300:])
plt.plot(df['MA for 10 days'][-300:])
plt.plot(df['MA for 20 days'][-300:])
plt.plot(df['MA for 50 days'][-300:])
plt.xlabel('Date', fontsize=14)
plt.ylabel('Close Price USD ($)', fontsize=14)
plt.legend(['Close', 'MA for 10 days', 'MA for 20 days', 'MA for 50 days'], loc='upper right')
plt.show()
LSTMのためのデータを準備
# Close(終値)のデータ
data = df.filter(['Close'])
dataset = data.values
# データを0〜1の範囲に正規化
scaler = MinMaxScaler(feature_range=(0,1))
scaled_data = scaler.fit_transform(dataset)
scaled_data
LSTMトレーニングデータを準備
# 全体の80%をトレーニングデータとして扱う
training_data_len = int(np.ceil( len(dataset) * .8 ))
# どれくらいの期間をもとに予測するか
window_size = 60
train_data = scaled_data[0:int(training_data_len), :]
# train_dataをx_trainとy_trainに分ける
x_train, y_train = [], []
for i in range(window_size, len(train_data)):
x_train.append(train_data[i-window_size:i, 0])
y_train.append(train_data[i, 0])
# numpy arrayに変換
x_train, y_train = np.array(x_train), np.array(y_train)
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
LSTMモデルの実装と学習
model = Sequential()
model.add(LSTM(units=50,return_sequences=True,input_shape=(x_train.shape[1], 1)))
model.add(Dropout(0.2))
model.add(LSTM(units=50,return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=50,return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=50))
model.add(Dropout(0.2))
model.add(Dense(units=1))
model.compile(optimizer='adam', loss='mean_squared_error')
history = model.fit(x_train, y_train, batch_size=32, epochs=100)
どういうモデルにするかが問題ですが、今回はLSTMを用いて株価を予測するにはどれくらい学習すべきかを書いた論文「Stock Market Prediction Using LSTM Recurrent Neural Network」に近い実装となっていそうな「mwitiderrick/stockprice」を参考にしました。LSTMの層にそれぞれDropoutが接続されているので、特徴を見つけながら一部は忘れて強くなっていくイメージですね。最適化アルゴリズムにadam、損失関数にはMSE(平均二乗誤差)を指定しています。
これを実行すると下記のように学習が始まります。予測値と正解値を計算して、損失(loss)が最小になるように学習していきます。しばらく眺めているとlossの値が小さくなっていくはずです。
また、batch_size(バッチサイズ)とepochs(エポック)を指定していますが、これはトレーニングデータをバッチサイズを元にして分割して、分割した数だけ学習を繰り返します。さらにその学習をエポック数回繰り返します。
model.summary()
テストデータでLSTMモデルを検証する
# テストデータを作成
test_data = scaled_data[training_data_len - window_size: , :]
x_test = []
y_test = dataset[training_data_len:, :]
for i in range(window_size, len(test_data)):
x_test.append(test_data[i-window_size:i, 0])
# numpy arrayに変換
x_test = np.array(x_test)
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1 ))
# 予測を実行する
predictions = model.predict(x_test)
predictions = scaler.inverse_transform(predictions)
# 二乗平均平方根誤差(RMSE): 0に近いほど良い
rmse = np.sqrt(np.mean(((predictions - y_test) ** 2)))
print(rmse)
# 決定係数(r2) : 1に近いほど良い
r2s = r2_score(y_test, predictions)
print(r2s)
train = data[:training_data_len]
valid = data[training_data_len:]
valid['Predictions'] = predictions
plt.figure(figsize=(16,6))
plt.title('Model')
plt.xlabel('Date', fontsize=14)
plt.ylabel('Close Price USD ($)', fontsize=14)
plt.plot(train['Close'])
plt.plot(valid[['Close', 'Predictions']])
plt.legend(['Train', 'Val', 'Predictions'], loc='lower right')
plt.show()
まとめ
Kerasなどのディープラーニングライブラリも進化しているので、時系列データを扱ってLSTMで予測をすることは意外に簡単にできるようになってきています。実際には、学習の工夫や精度の検証など細かい部分が必要になりますが大枠は変わりません。また、DataFrameやnumpy array、データ分割の扱いなど、機械学習を行う際は同じような実装パターンに出会うと思いますので、慣れていけば有益なスキルになると思います。
関連記事
- 2022-09-07
- テクノロジー