- ディープニューラルネットワークの実装方法(ソースコードつき)
- ディープニューラルネットワークでの株価予測の方法
ディープニューラルネットワークによる株価予測の概要
予測は以下の流れで行います。
つまり,30日後の株価を予測する回帰モデルになります!
![](https://icochan1.net/wp-content/uploads/2023/02/04f86ea9c104d100d663feb8a9a65769-1-1024x576.png)
とりあえずモデルを作って予測をすることが目的なので,簡単なモデルを紹介したいと思います。
他の手法でも予測を行っているので,ぜひご覧ください。
![](https://icochan1.net/wp-content/uploads/2023/02/7d2a8a5d380f463388d1c8d4512bef57-2-300x169.png)
![](https://icochan1.net/wp-content/uploads/2023/02/40dcbe9d88c96297b642179a653642d8-1-300x169.png)
![](https://icochan1.net/wp-content/uploads/2023/02/c64c5ece666a6407486987541305a212-1-300x169.png)
![](https://icochan1.net/wp-content/uploads/2023/02/60275ab58ebd7cd921d15fb49998721b-1-300x169.png)
事前準備
まずは,環境についてです。
- Python 3.8.15
- macOS Monterey 12.5
必要なライブラリは以下のようになります。ない場合にはpip
やconda
で入れてください。
必要なライブラリ
- pandas
- numpy
- tensorflow
- datetime
- pandas_datareader
Macでのtensorflowの入れ方はこちらの記事をご覧ください。
![](https://icochan1.net/wp-content/uploads/2022/09/d3f3f00cf1a7f0b7549c20d4afc63a1b-2-300x169.png)
ライブラリのインポート
データを扱うのに必要なライブラリのインポートを行います。
import pandas as pd
import numpy as np
from datetime import datetime
株価情報の取得
主要な株価指数の取得
予測のための説明変数として,日経平均株価などを取得します。
今回は,日経225,S&P500,ナスダック総合指数を取得しています。
from pandas_datareader import data
marketData = ['NIKKEI225','SP500','NASDAQCOM']
df_market = data.DataReader(marketData,'fred','2014-01-01', '2023-1-31').asfreq("D")
df_market = df_market.fillna(method='ffill')
df_market = df_market.dropna(how='any')
3行目:df_market = data.DataReader…
指数を2014年1月1日から2023年1月31日まで取得しています。
4行目:df_market = df_market.fillna…
欠損値を埋めています。
5行目:df_market = df_market.dropna…
欠損値がある場所は削除しています。
株価取得の詳しい内容については以下をご覧ください。
![](https://icochan1.net/wp-content/uploads/2022/09/0ae7c62e50dc705df75843b104ce66cd-1-300x169.jpg)
主要な株価指数の前処理
株価指数そのままでは学習しにくいので,移動平均との乖離を計算します。
ここは精度に関係するので試行錯誤する必要があります。
# 各指数の移動平均との乖離率を算出する
for index_name in df_market.columns:
for i in [5,10,30,60,90,120]:
df_market[index_name + "_" + str(i) + "days_diffrol"] =\
(df_market[index_name].rolling(i).mean() - df_market[index_name]) / df_market[index_name].rolling(i).mean()
# 生データは削除する
df_market = df_market.drop(columns=index_name)
予測する企業の株価を取得
予測したい企業の株価を取得します。
CODE=
の部分は予測したい企業の株価コードを指定します。
今回は4755
の企業の予測をしています。
# 予測する企業の株価データを取得
from pandas_datareader.stooq import StooqDailyReader
CODE = 4755
CODE_str = str(CODE) + ".JP"
start = datetime(2014, 1, 1)
end = datetime(2023, 1, 31)
df_target = StooqDailyReader(CODE_str, start=start, end=end).read()
df_target = df_target.sort_values('Date')
df_target = pd.DataFrame(df_target).asfreq("D", method="ffill")
5行目:start = datetime(2014, 1, 1)
取得する範囲のスタートを設定します。end
も同じです。
8行目:df_target = StooqDailyReader…
データを取得します。
9行目:df_target = df_target.sort_values(‘Date’)
df_target
には最近のデータから順番に入っているので昇順にします。
10行目:df_target = pd.DataFrame…
データの欠損値処理をしています。
予測対象の作成
予測するのは,30日後の株価です。
# 目的変数の作成(30日後の終値)
df_target["target"] = df_target["Close"].shift(-30)
# 不要な行と列を削除
df_target = df_target.dropna(how='any')
2行目:df_target[“target”] = …
Close
に入っている終値を30日ずらすことで,30日後の終値を取得しています。
データの整理
データの結合
これまでに作成したデータを結合して1つのdataframeにします。
# データの結合
df = pd.merge(df_target, df_market, how='left', left_index=True, right_index=True)
df = df.dropna(how='any')
学習データとテストデータに分割
今回は,2021年までのデータを使って2022年の予測を行います。
# トレインとテストに分割
df_train = df[:"2021"]
df_test = df["2022":]
# 目的変数と説明変数に分割
X_train = df_train.drop("target", axis=1)
y_train = df_train["target"]
X_test = df_test.drop("target", axis=1)
y_test = df_test["target"]
データを標準化する
ニューラルネットワークに入れる説明変数は標準化や正規化といった前処理をする必要があります。
今回はscikit-learnを使って標準化しました。
#標準化を行う
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
4行目:scaler.fit(X_train)
学習データを使って標準化のための変数を取得しています。
6行目:X_train = scaler.transform(X_train)
学習データを標準化しています。
7行目:X_test = scaler.transform(X_test)
テストデータを標準化しています。
モデルの作成
ディープニューラルネットワークでの学習
いよいよ作成したデータを学習させます。
# 学習
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
from tensorflow.keras.optimizers import Adam
# ニューラルネットワーク
model = Sequential()
# Denseは全結合層
model.add(Dense(128, input_dim=23, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(1))
# パラメタ
loss = 'mean_squared_error'
optimizer = Adam()
metrics = ['accuracy']
model.compile(loss=loss, optimizer=optimizer, metrics=metrics)
history = model.fit(X_train, y_train, epochs=200, batch_size=32) # 学習
6行目:model = Sequential()
モデルを定義しています。
8行目:model.add(Dense…
説明変数は23個で,中間層1層目は128ノードとしています。
Dense
は全結合という意味です。
9行目〜11行目:model.add(Dense…
中間層を追加しています。
2層目を64ノード,3層目を32ノード,4層目を8ノード,出力層を1ノードとしています。
12行目:model.add(Dense(1, activation=’relu’))
出力は30日後の株価であるので,出力層は1ノードになります。
15行目:loss = ‘mean_squared_error’
損失関数を定義しています。
16行目:optimizer = Adam()
最適化アルゴリズムを指定しています。今回はAdamを使用しています。
17行目:metrics = [‘accuracy’]
評価関数を定義しています。
19行目:model.compile(…
モデルをコンパイルしています。
21行目:history =
モデルにデータを入れて学習させます。
下のような感じで学習が進めばOKです。
Epoch 195/200
88/88 [==============================] – 0s 638us/step – loss: 12125.3743 – accuracy: 0.0000e+00
Epoch 196/200
88/88 [==============================] – 0s 728us/step – loss: 11865.1447 – accuracy: 0.0000e+00
Epoch 197/200
88/88 [==============================] – 0s 631us/step – loss: 11608.6920 – accuracy: 0.0000e+00
Epoch 198/200
88/88 [==============================] – 0s 549us/step – loss: 11603.5125 – accuracy: 0.0000e+00
Epoch 199/200
88/88 [==============================] – 0s 523us/step – loss: 11968.9549 – accuracy: 0.0000e+00
Epoch 200/200
88/88 [==============================] – 0s 476us/step – loss: 11611.8031 – accuracy: 0.0000e+00
結果の保存
予測結果を保存して精度を確認します。
df_result
に結果をまとめます。
# 予測値と実値との比較
df_result = pd.DataFrame()
df_result["Price"] = df_target["Close"]["2022-01-31":]
df_result["true"] = y_test.values[:366-30]
df_result["pred"] = model.predict(X_test)[:366-30]
![](http://image.moshimo.com/af-img/0665/000000051841.jpg)
結果の確認
matplotlibで結果を表示してみましょう。
import matplotlib.pyplot as plt
plt.figure()
df_result[["true","pred"]].plot(figsize=(6, 4))
![](https://icochan1.net/wp-content/uploads/2023/02/DNN-1024x683.png)
青線は実際の株価,オレンジ線が予測結果を示しています。
大まかな傾向はなんとなく予測できているようですが,細かい動きは予測がうまくいっていません。
ニューラルネットワークと比較すると若干精度が上がっている気もします。
![](https://icochan1.net/wp-content/uploads/2023/02/60275ab58ebd7cd921d15fb49998721b-1-300x169.png)
使えるモデルにするためには,ノード数を変えるなどパラメータチューニングを行う必要があります。
他の精度を上げる方法は以下の方法が考えられます。
精度を上げる方法
- 他のアルゴリズムを使用する
- 他の変数を使って予測する
ソースコードまとめ
今回使用したコードはこちらになります。
import pandas as pd
import numpy as np
from datetime import datetime
# 市場データの取得
from pandas_datareader import data
marketData=['NIKKEI225','SP500','NASDAQCOM']
df_market = data.DataReader(marketData,'fred','2014-01-01', '2023-1-31').asfreq("D")
df_market = df_market.fillna(method='ffill')
df_market = df_market.dropna(how='any')
# 各指数の移動平均との乖離率を算出する
for index_name in df_market.columns:
for i in [5,10,30,60,90,120]:
df_market[index_name + "_" + str(i) + "days_diffrol"] =\
(df_market[index_name].rolling(i).mean() - df_market[index_name]) / df_market[index_name].rolling(i).mean()
# 生データは削除する
df_market = df_market.drop(columns=index_name)
# 予測する企業の株価データを取得
from pandas_datareader.stooq import StooqDailyReader
CODE = 4755
CODE_str = str(CODE) + ".JP"
start = datetime(2014, 1, 1)
end = datetime(2023, 1, 31)
df_target = StooqDailyReader(CODE_str, start=start, end=end).read()
df_target = df_target.sort_values('Date')
df_target = pd.DataFrame(df_target).asfreq("D", method="ffill")
# 目的変数の作成(30日後の終値)
df_target["target"] = df_target["Close"].shift(-30)
# 不要な行と列を削除
df_target = df_target.dropna(how='any')
# データの結合
df = pd.merge(df_target, df_market, how='left', left_index=True, right_index=True)
df = df.dropna(how='any')
# トレインとテストに分割
df_train = df[:"2021"]
df_test = df["2022":]
# 目的変数と説明変数に分割
X_train = df_train.drop("target", axis=1)
y_train = df_train["target"]
X_test = df_test.drop("target", axis=1)
y_test = df_test["target"]
#標準化を行う
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
# 学習
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
from tensorflow.keras.optimizers import Adam
# ニューラルネットワーク
model = Sequential()
# Denseは全結合層
model.add(Dense(128, input_dim=23, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(1))
# パラメタ
loss = 'mean_squared_error'
optimizer = Adam()
metrics = ['accuracy']
model.compile(loss=loss, optimizer=optimizer, metrics=metrics)
history = model.fit(X_train, y_train, epochs=200, batch_size=32) # 学習
# 予測値と実値との比較
df_result = pd.DataFrame()
df_result["Price"] = df_target["Close"]["2022-01-31":]
df_result["true"] = y_test.values[:366-30]
df_result["pred"] = model.predict(X_test)[:366-30]
import matplotlib.pyplot as plt
plt.figure()
df_result[["true","pred"]].plot(figsize=(6, 4))
コメント