概要
株価、為替、天気、動画など時系列データの予測でよく使われるディープラーニングの代表的手法RNN(再帰型ニューラルネットワーク)の拡張バージョンに、LSTM(Long short-term memory)と呼ばれるモデルがある。今回はLSTM Many to Oneモデルを実装して、複数銘柄(例:10銘柄)の株価から翌日の上がる株を探ってみる。
環境
keras 2.2.5 LSTM
Google Colab CPU/GPU/TPU
Ubuntu 18.04.3 LTS
Python 3.6.8
Numpy 1.17.3
Pandas 0.25.2
sklearn 0.21.3
実装
Many-to-Oneモデルの例として、以下2銘柄から翌日の上がる株を探る。
# -*- coding: utf-8 -*- import numpy import pandas import matplotlib.pyplot as plt from sklearn import preprocessing from keras.models import Sequential from keras.layers.core import Dense, Activation from keras.layers.recurrent import LSTM class Predict: def __init__(self): self.length_of_sequences = 10 self.in_out_neurons = 1 self.hidden_neurons = 300 self.batch_size = 32 self.epochs = 100 self.percentage = 0.8 # データ用意 def load_data(self, data, n_prev): x, y = [], [] for i in range(len(data) - n_prev): x.append(data.iloc[i:(i+n_prev)].values) y.append(data.iloc[i+n_prev].values) X = numpy.array(x) Y = numpy.array(y) return X, Y # モデル作成 def create_model(self) : Model = Sequential() Model.add(LSTM(self.hidden_neurons, batch_input_shape=(None, self.length_of_sequences, self.in_out_neurons), return_sequences=False)) Model.add(Dense(self.in_out_neurons)) Model.add(Activation("linear")) Model.compile(loss="mape", optimizer="adam") return Model # 学習 def train(self, x_train, y_train) : Model = self.create_model() Model.fit(x_train, y_train, self.batch_size, self.epochs) return Model if __name__ == "__main__": predict = Predict() nstocks = 2; # 銘柄毎に学習、予測、表示 for istock in range(1, nstocks + 1): # データ準備 data = None data = pandas.read_csv('/content/drive/My Drive/LSTM/csv/' + str(istock) + '_stock_price.csv') data.columns = ['date', 'open', 'high', 'low', 'close'] data['date'] = pandas.to_datetime(data['date'], format='%Y-%m-%d') # 終値のデータを標準化 data['close'] = preprocessing.scale(data['close']) data = data.sort_values(by='date') data = data.reset_index(drop=True) data = data.loc[:, ['date', 'close']] # 割合で学習、試験データ分割 split_pos = int(len(data) * predict.percentage) x_train, y_train = predict.load_data(data[['close']].iloc[0:split_pos], predict.length_of_sequences) x_test, y_test = predict.load_data(data[['close']].iloc[split_pos:], predict.length_of_sequences) # 学習 model = predict.train(x_train, y_train) # 試験 predicted = model.predict(x_test) result = pandas.DataFrame(predicted) result.columns = [str(istock) + '_predict'] result[str(istock) + '_actual'] = y_test # 表示 result.plot() plt.show() # 翌日株価比較 current = result.iloc[-1][str(istock) + '_actual'] predictable = result.iloc[-1][str(istock) + '_predict'] if (predictable - actual) > 0: print(f'{istock} stock price of the next day INcreases: {predictable-actual:.2f}, predictable:{predictable:.2f}, current:{current:.2f}') else: print(f'{istock} stock price of the next day DEcreases: {actual-predictable:.2f}, predictable:{predictable:.2f}, current:{current:.2f}')
またソースコード、csvファイルは、https://github.com/soarbear/stocks-lstm-kerasへ公開した。
結果
![keras lstmで複数銘柄の株価予測](https://memo.soarcloud.com/wp-content/uploads/2019/10/stocks-letm-keras.jpg)
【追記】再現性
毎回学習してから予測の結果が変わるので、再現性、生産性がない。ニューロンの重みやバイアスの初期値など【Randomness in Initialization, Regularization, Layers, Optimization】がRandomであり、以下の例として、SEED_IDを固定することによって、予測結果の再現が確認できた。ただしepochsは、SEED_IDを固定しないRandomのほうよりlossがいかに最小まで収束するかを確かめる必要がある。
import numpy as np import tensorflow as tf import random as rn import os os.environ['PYTHONHASHSEED'] = '0' from keras import backend as K session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1) sess = tf.Session(graph=tf.get_default_graph(), config=session_conf) K.set_session(sess) ...... def fix_seed(): np.random.seed(SEED_ID) rn.seed(SEED_ID) tf.set_random_seed(SEED_ID) ...... def create_model(self) : Model = Sequential() fix_seed() Model.add(LSTM(self.hidden_neurons, batch_input_shape=(None, self.length_of_sequences, self.in_out_neurons), return_sequences=False)) fix_seed() Model.add(Dense(self.in_out_neurons)) Model.add(Activation("linear")) Model.compile(loss="mape", optimizer="adam") return Model ......
また、2のKeras公式資料もあわせて確認しておく。
しかし、ニューロンの重みやバイアスの初期値が固定するより、ランダムのほうは結果の多様性が現われる。複数のモデル(30以上?)より交差検証の手法で良いモデルを選ぶのが、まさに統計の務めではないかと考えさせられる機会となる。
【追記】学習状況をスマホに記録
学習状況をスマホでモニタしたい際、アプリHyperdashが使える。以下コードを実行する。学習状況の履歴がスマホに残る。
!pip install hyperdash from hyperdash import monitor_cell !hyperdash signup --github
%%monitor_cell 'xxx'
参考文献
1、LSTMネットワークを理解する(英文原稿)、Christopher Olah氏
2、開発中にKerasを用いて再現可能な結果を得るには?、Keras公式資料