時系列分析とは、ある一定期間のデータの傾向の変化を分析することである。
時系列解析には様々な応用がある。
その1つが、過去の値から将来の価値を予測することである。
将来の株価予測は、そのような応用の最も良い例でしょう。
今回は、リカレントニューラルネットワークの助けを借りて、どのように時系列解析を行うかを見ていきます。
今回は、アップル社(AAPL)の過去5年間の株価から、将来の株価を予測することにします。
データセット
今回使用するデータは、ヤフーファイナンスからダウンロードすることができます。
アルゴリズムのトレーニングのために、我々は2013年1月1日から2017年12月31日までのAppleの株価を使用する予定です。
予測のために、我々は2018年1月の月のAppleの株価を使用する予定です。
そこで、アルゴリズムの性能を評価するために、2018年1月の月の実際の株価もダウンロードします。
それでは、データがどのように見えるか見てみましょう。
5年分のデータを含むAppleの株価の学習ファイルを開いてください。
7つのカラムが含まれていることがわかります。
日付、始値、高値、安値、終値、Adj Close、出来高です。
私たちは始値の株価を予測するので、残りのカラムには興味がありません。
始値の株価を日付に対してプロットすると、次のようなプロットになります。
トレンドは非常に非線形であり、この情報を使ってトレンドを捉えるのは非常に困難であることがわかります。
そこで、LSTMの威力を発揮します。
LSTM(Long Short-Term Memory network)とは、リカレントニューラルネットワークの一種で、過去の情報を記憶し、その情報を考慮しながら将来の値を予測することができる。
前置きはこのくらいにして、LSTMがどのように時系列解析に使われるかを見ていこう。
将来の株価を予測する
株価の予測は、他の機械学習問題と同様で、特徴のセットが与えられ、それに対応する値を予測しなければならない。
どのような機械学習問題でも、その解を求めるために行うのと同じステップを踏むことになる。
以下のステップを踏んでください。
インポートライブラリ
いつものように、まず必要なライブラリをインポートします。
以下のスクリプトを実行してください。
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
データセットのインポート
以下のスクリプトを実行すると、データセットがインポートされます。
今回は、EドライブのDatasetsフォルダにデータを保存しています。
パスは適宜変更してください。
apple_training_complete = pd.read_csv(r'E:Datasetspple_training.csv')
先ほど述べたように、私たちは株価の始値にしか興味がありません。
そこで、学習セットからすべてのデータをフィルタリングし、Open 列の値のみを保持することにします。
以下のスクリプトを実行します。
apple_training_processed = apple_training_complete.iloc[:, 1:2].values
データの正規化
経験則として、ニューラルネットワークを使用するときはいつでも、データを正規化またはスケールする必要があります。
ここでは sklear.preprocessing
ライブラリの MinMaxScaler
クラスを使用して、データを 0 から 1 の間でスケーリングします。
以下のスクリプトを実行する。
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range = (0, 1))
apple_training_scaled = scaler.fit_transform(apple_training_processed)
学習データを正しい形状に変換する
先ほども言いましたが、時系列問題では、T日~N日(Nは任意のステップ数)のデータから、T時の値を予測する必要があります。
今回は、過去60日間の始値株価をもとに、データの始値株価を予測することにします。
いろいろな数字を試してみたところ、過去60回のタイムステップを使用したときに最も良い結果が得られることがわかりました。
様々な数値を試してみて、自分のアルゴリズムがどのように機能するかを確認することができます。
特徴セットは過去60日間のオープニング株価を含み、ラベルまたは従属変数は61日目の株価でなければなりません。
以下のスクリプトを実行して、特徴量とラベルのセットを作成します。
features_set = []
labels = []
for i in range(60, 1260):
features_set.append(apple_training_scaled[i-60:i, 0])
labels.append(apple_training_scaled[i, 0])
上のスクリプトでは、feature_set
とlabels
という2つのリストを作成しています。
学習データのレコード数は1260である。
61 番目のレコードからループを実行し、それまでの 60 個のレコードを feature_set
リストに格納する。
61 番目のレコードは labels
リストに格納される。
学習用に使用する前に、feature_set
と labels
の両リストをnumpy配列に変換する必要があります。
以下のスクリプトを実行します。
features_set, labels = np.array(features_set), np.array(labels)
LSTMを学習させるために、データをLSTMが受け入れる形に変換する必要があります。
データを3次元に変換する必要がある。
1次元目はデータセットのレコード数(行数)であり、この例では1260である。
2次元目は時間ステップの数で60、最後の次元は指標の数です。
今回はOpenという1つの特徴しか使わないので、指標の数は1つになります。
以下のスクリプトを実行します。
features_set = np.reshape(features_set, (features_set.shape[0], features_set.shape[1], 1))
LSTMの学習
我々はデータを前処理し、必要な形式に変換した。
次はLSTMを作成する番だ。
これから作成するLSTMモデルは複数のレイヤーを持つ逐次モデルである。
我々は4つのLSTM層をモデルに追加し、将来の株価を予測する密な層を追加する予定である。
まず、モデルを作成するために必要なライブラリをインポートしましょう。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
上のスクリプトでは keras.models
ライブラリから Sequential
クラスを、 keras.layers
ライブラリから Dense
、LSTM
、Dropout
クラスをインポートしています。
最初のステップとして、Sequential
クラスのインスタンスを作成する必要があります。
このクラスがモデルクラスとなり、LSTM、Dropout、Dense の各レイヤーをこのモデルに追加していきます。
以下のスクリプトを実行してください。
model = Sequential()
LSTMとDropoutレイヤーの作成
先ほど作成したモデルにLSTMのレイヤーを追加してみましょう。
以下のスクリプトを実行してください。
model.add(LSTM(units=50, return_sequences=True, input_shape=(features_set.shape[1], 1)))
逐次モデルにレイヤーを追加するには、add
メソッドを使用します。
addメソッドの中で、LSTMのレイヤーを渡します。
LSTM レイヤーの最初のパラメータは、レイヤーに必要なニューロンまたはノードの数です。
2つ目のパラメータはreturn_sequencesで、モデルにさらにレイヤーを追加していくので true に設定します。
input_shapeの最初のパラメータはタイムステップ数で、最後のパラメータは指標の数です。
それでは、ドロップアウト層をモデルに追加してみましょう。
ドロップアウト層はオーバーフィットを防ぐために追加されます。
オーバーフィットとは、機械学習モデルがテストデータと比較してトレーニングデータでより良い性能を発揮する現象のことです。
以下のスクリプトを実行し、ドロップアウト層を追加してください。
model.add(Dropout(0.2))
さらに3つのLSTM層とドロップアウト層を追加してみましょう。
以下のスクリプトを実行してください。
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))
密なレイヤーを作成する
モデルをより堅牢にするために、モデルの最後に密な層を追加する。
密な層のニューロン数は、出力の単一の値を予測したいので、1に設定されます。
model.add(Dense(units = 1))
モデルコンパイル
最後に、学習データでLSTMを学習させる前に、LSTMをコンパイルする必要があります。
以下のスクリプトでモデルをコンパイルします。
model.compile(optimizer = 'adam', loss = 'mean_squared_error')
コンパイルはSequentialモデルオブジェクト(ここでは “model”)に対して行われます。
損失関数として平均二乗誤差を使用し、損失の低減やアルゴリズムの最適化のためにadamオプティマイザーを使用しています。
アルゴリズム学習
さて、ここまでのステップで定義したモデルを学習させる時が来ました。
そのためには、以下のように model
に対して fit
メソッドを呼び出し、学習用の特徴量とラベルを渡します。
model.fit(features_set, labels, epochs = 100, batch_size = 32)
ハードウェアの種類によっては、モデルの学習に時間がかかる場合があります。
LSTMのテスト
LSTMの学習が完了したので、次はテストセットで2018年1月の始値株価を予測し、アルゴリズムの性能をテストする番です。
しかし、トレーニングデータで行ったように、テストデータも正しい形式に変換する必要があります。
まずは、テストデータをインポートしましょう。
以下のスクリプトを実行します。
apple_testing_complete = pd.read_csv(r'E:Datasetspple_testing.csv')
apple_testing_processed = apple_testing_complete.iloc[:, 1:2].values
上記のスクリプトでは、テストデータをインポートし、トレーニングデータと同様に、テストデータから始値の株価を含む列を除いて、すべての列を削除しています。
2018年1月の始値株価を日付に対してプロットすると、以下のようなグラフが表示されるはずです。
非線形性の強いトレンドになっていることがわかります。
全体として、月初に小さく上昇し、月末に下降する傾向が見られ、その間に株価の上昇と下降が若干見られます。
このようなトレンドを予測することは極めて困難である。
では、実際に学習させたLSTMがこのようなトレンドを予測できるか見てみましょう。
テストデータを正しい形式に変換する
2018年1月の各日について、過去60日間の始値株価を含むフィーチャーセットが必要です。
1月1日については、過去60日間の株価が必要です。
そのためには、前処理の前に学習データとテストデータを連結させる必要があります。
そのためには、以下のスクリプトを実行します。
apple_total = pd.concat((apple_training_complete['Open'], apple_testing_complete['Open']), axis=0)
では、テスト用の入力を用意しましょう。
各日の入力には過去60日間の始値(opening stock prices)が必要です。
つまり、2018年1月の20日間のテスト用オープニング株価と、トレーニングセット用の過去60日間の株価が必要です。
以下のスクリプトを実行し、これら80個の値を取得します。
test_inputs = apple_total[len(apple_total) - len(apple_testing_complete) - 60:].values
トレーニングセットで行ったように、テストデータもスケールする必要があります。
以下のスクリプトを実行します。
test_inputs = test_inputs.reshape(-1,1)
test_inputs = scaler.transform(test_inputs)
データをスケーリングしたので、1月の過去60件の株価を含む最終的なテスト入力セットを準備しましょう。
次のスクリプトを実行します。
test_features = []
for i in range(60, 80):
test_features.append(test_inputs[i-60:i, 0])
最後に、データをLSTMの入力として使えるように3次元形式に変換する必要がある。
以下のスクリプトを実行する。
test_features = np.array(test_features)
test_features = np.reshape(test_features, (test_features.shape[0], test_features.shape[1], 1))
予測を行う
さて、いよいよ魔法を見るときです。
テストデータの前処理を行ったので、それを使って予測を行うことができます。
そのためには、学習させたモデルに対して predict
メソッドを呼び出すだけでよいのです。
以下のスクリプトを実行してください。
predictions = model.predict(test_features)
データをスケーリングしたので、LSTMによって作られる予測もスケーリングされる。
スケーリングされた予測値を実際の値に戻す必要があります。
これを行うには、学習時に作成したスケーラーオブジェクトの ìnverse_transform
メソッドを使用します。
以下のスクリプトを見てください。
predictions = scaler.inverse_transform(predictions)
最後に、我々のアルゴリズムが将来の株価をどの程度予測したかを見てみましょう。
以下のスクリプトを実行してみてください。
plt.figure(figsize=(10,6))
plt.plot(apple_testing_processed, color='blue', label='Actual Apple Stock Price')
plt.plot(predictions , color='red', label='Predicted Apple Stock Price')
plt.title('Apple Stock Price Prediction')
plt.xlabel('Date')
plt.ylabel('Apple Stock Price')
plt.legend()
plt.show()
出力は以下のようになります。
出力では、青い線が2018年1月の実際の株価を表し、赤い線が予測された株価を表しています。
我々のアルゴリズムが全体的なトレンドを捉えることができたことがよくわかります。
また、予測された株価は、最初に強気のトレンドがあり、最後に弱気または下降のトレンドがあることがわかります。
結論
長短期記憶ネットワーク(LSTM)は、時系列解析に最もよく使われるニューラルネットの一つである。
LSTMは以前の情報を記憶する能力があるため、このようなタスクに理想的である。
この記事では、Appleの株価予測にLSTMを使用する方法を見た。
GoogleやMicrosoftのような他の組織の株をYahoo Financeからダウンロードし、アルゴリズムがトレンドを捉えられるかどうか見てみることをお勧めします。