bookloveru2

2021年6月14日11 分

pythonで株価分析⑮【コピペでOK! 多層パーセプトロンで株価予測モデルを構築する(機械学習)】

最終更新: 2021年11月1日

皆様こんにちは。

今回はpythonで株価分析の第15幕です(・ω・)ノ

表題の通り、機械学習を利用して株価予測モデルを構築していきます。

では、早速いってみましょう(・ω・)ノ


目次

多層パーセプトロンとは?を30秒で解説

株価予測モデル構築

株価予測モデル解説

pythonコード解説

python一括コード

Facebookが開発した機械学習ライブラリで株価を予測


❶ 多層パーセプトロンとは?を30秒で解説

パーセプトロンは、下図の〇(赤丸)のことです。

例:ここに1本のワインがあるとします。

これが「赤ワイン」か「白ワイン」かを判定する為に、

【年数・アルコール度数・色合い】

という3つの情報を利用して結果を判定します。

左側から、入力層、中間層、出力層と層がたくさんある為、多層パーセプトロンと言います。

画像は国内最強の頭脳集団:PFNのchainerチュートリアルより👆

https://tutorials.chainer.org/ja/13_Basics_of_Neural_Networks.html

多層パーセプトロンの説明は以上です(`・ω・´)ゞ

❷ 株価予測モデル構築

では、ここからは多層パーセプトロンを利用して株価予測モデルを構築していきます。

ワイン判定の様に

【年数・アルコール度数・色合い】

という情報の、株価バージョンを決めて、株価予測モデルを構築します。

今回の株価バージョンでは、

【金利・原油価格・ダウ平均株価・出来高】

を情報として利用します。

上記4点を基に、多層パーセプトロンで構築した株価予測モデルの結果を下記に示します。

・多層パーセプトロンで構築したモデル:株価の上下予測

・対象銘柄:バンク・オブ・アメリカ【BAC】

・学習期間:2016.6.14~2021.6.13(5年間)

・予測モデルの精度(結果):54.9%

となりました。

これは、【金利・原油価格・ダウ平均株価・出来高】という情報を利用すると約55%の確率で株価の上下予測が可能❕ということを意味します(`・ω・´)ゞ

まず、バンク・オブ・アメリカの5年間の株価を見ていきます。

2016年ちゅばんより上昇傾向。コロナショックで死亡。異次元緩和で再復活という感じです👇

https://finance.yahoo.com/quote/BAC?p=BAC

ここで、今回作成した予測モデルの出力結果です👇

ROC曲線は、イマイチ。予測が当たるかは、1/2といった所です。

(´;ω;`)ウッ…

そう簡単には、億万長者になれそうもありません( ノД`)シクシク…👇

❸ 株価予測モデル解説

株価予測モデル

作成した予測モデルは、「翌日の株価が上昇したら、1」を「翌日の株価が下落したら、0」を出力します。

予測の「1と0」の個数を、実際の値「1と0」の個数と比較し、その正解率が54.9%となっております。

対象期間の学習率:学習データ7割、テストデータ3割

さて、予測モデルの結果ですが、下記の通り、1問目から間違っています(´;ω;`)ウゥゥ👇

という計算の結果、正解率は約55%でした(・ω・)ノ

【金利・原油価格・ダウ平均株価・出来高】という情報を利用すると約55%の確率で株価の上下予測が可能❕

ていうか、半分くらいしか当たらんやんけ(*ノωノ)

という感想でした。

ま、選択した情報が大したこと無かったのかなぁ~。。

以上でモデルの解説は終わりです。次は、pythonコードです。

❹ pythonコード解説

#@title 多層パーセプトロンで株価予測
 
import datetime
 
import fix_yahoo_finance as yf
 
import matplotlib.pyplot as plt
 
import seaborn as sns
 
%matplotlib inline
 
import warnings
 
warnings.filterwarnings('ignore')
 

 
#スタート日を決める
 
start = "2016-6-14" #@param {type:"string"}
 

 
#①株価を取得する
 
start = start #株価を取得するスタート日を決める
 
end = datetime.date.today() #現在までの営業日(今日 =today)を取得する最終日とする
 
codelist = ["^DJI","^N225","^FTSE","000001.SS","IMOEX.ME","^BSESN","^BVSP", "BTC-USD","^TNX","GC=F","CL=F"]
 
#コードリストに取得したい銘柄を入れる アメリカ 日本 イギリス 中国 ロシア インド ブラジル ビットコ 10年金利 金 原油
 
#②取得した株価の内、終値をdata2に格納する
 
data2 = yf.download(codelist, start=start, end=end)["Adj Close"] .dropna()
 
data2.rename(columns={'^DJI':'ダウ',
 
'^N225':'日経平均',
 
'^FTSE':'イギリス',
 
"000001.SS":'中国',
 
'IMOEX.ME':'ロシア',
 
'^BSESN':'インド',
 
'^BVSP':'ブラジル',
 
'BTC-USD':'ビットコ',
 
'^TNX':'10 Year Treasury',
 
"GC=F":"金",
 
"CL=F":"原油"},inplace=True)
 
data2
 

実行結果👇

スタート日から今日現在までの世界主要株価+指数の終値データが作成されます。


# 前処理開始。分析用のXとyを作成。
 
import pandas_datareader as pdr
 
from sklearn.model_selection import train_test_split
 
from sklearn.metrics import accuracy_score, precision_score, recall_score
 
from sklearn.linear_model import LogisticRegression
 
from sklearn.neural_network import MLPClassifier
 
from sklearn.pipeline import make_pipeline
 
from sklearn.preprocessing import StandardScaler
 

 
ticker = "BAC" #@param {type:"string"}
 
df = pdr.get_data_yahoo(ticker, start, end)
 
# data2から説明変数追加
 
df["金利"] = data2['10 Year Treasury']
 
df["原油"] = data2['原油']
 
df["ダウ"] = data2['ダウ']
 
# 前日との差分をDiffへ格納
 
df["Diff"] = df["Adj Close"].diff()
 
# 終値×出来高を"出来高"へ格納
 
df["出来高"] = df["Adj Close"] * df["Volume"]

実行結果👇

説明変数として作成した【金利・原油価格・ダウ平均価格・Diff(前日との差分)・対象銘柄(今回はバンク・オブ・アメリカの)出来高】データがデータフレームに追加されます。


# 差分[Diff]を1行、上にずらして(.shift(-1))、xが0より大きい(つまり値上がりしていれば1。)
 
# xが0より大きくない(つまり値下がりしていれば0。)のラムダ式xを作成。.apply()でラムダ式をdf[Diff]へ格納して、df[y]を作成。
 
# yは未来の値。yが1なら明日の株価終値は上昇。つまりyは正解ラベル。
 
df["y"] = df["Diff"].apply(lambda x: 1 if x > 0 else 0).shift(-1)
 
# OpenとかHighとかをdfから削除.drop(["消すindex"],axis=1で列を指定)。.dropna()で欠損値のある行を削除。
 
df2 = df.drop(["Open", "High", "Low", "Close", "Volume", "Diff", "Adj Close"],axis=1,).dropna()
 
print('\033[35m'+"dfを表示\n"+'\033[0m', (df))
 
print('\033[35m'+"df2を表示\n"+'\033[0m', (df2))
 

 
# 説明変数
 
# yを列ごと削除してXを作成。
 
X = df2.drop(["y"], axis=1)
 
# 目的変数
 
# dfのyの値をyへ格納。yは正解ラベル。つまり(値下がりと値上がりの[0,1])だけのデータをyに充当。
 
y = df2["y"]
 
y

実行結果👇

前述のデータフレームから不必要な項目を削除。その際、未来の結果[0 or 1]を.shift(-1)で当日に持たせる。

未来の結果を[y]にいれて、それを表示。

つまり、正解・不正解が下図の黄色い枠(赤い丸で囲ったとこ)の中にある(0なら明日の株価下落。1なら明日の株価上昇)。


# デフォルトはtest_size=0.25で25%がテスト用、残りの75%が訓練用。ここでは、テスト用を30%に設定。
 
# デフォルトでは要素がシャッフルされて分割される。引数shuffle=Falseとするとシャッフルされずに先頭から順番に分割される。
 
# 機械学習のモデルの性能を比較するような場合、どのように分割されるかによって結果が異なってしまうため、乱数シードを固定して常に同じように分割されるようにする必要がある。
 
# ここでは使用していないが、要素がシャッフルされる場合、デフォルトでは実行するたびにランダムに分割される。引数random_stateを指定して乱数シードを固定すると常に同じように分割される。
 
# https://note.nkmk.me/python-sklearn-train-test-split/
 
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3,shuffle=False,)
 

 
# モデルに多層パーセプトロンを適用 [StandardScaler()で標準化] [shuffle=False先頭から順番に分割]
 
clf = make_pipeline(StandardScaler(), MLPClassifier(random_state=0, shuffle=False))
 
clf.fit(X_train,y_train)
 

 
print("\nX_train.shape", X_train.shape)
 
print("\ny_train.shape", y_train.shape)
 
print("\nX_test.shape", X_test.shape)
 
print("\ny_test.shape", y_test.shape)
 
print("\n学習用の説明変数 X_train -------------------------\n", X_train)
 
print("\n学習用の目的変数 y_train -------------------------\n", y_train)
 
print("\n評価用の説明変数 X_test -------------------------\n", X_test)
 
print("\n評価用の目的変数 y_test -------------------------\n", y_test)
 

 

 
# 学習させた内容を、テスト用データで確かめる。
 
predict = clf.predict(X_test)
 
print("\n予測値 predict --------------------------------------------------\n", predict)

実行結果👇

X_train.shape(679,4)は説明変数が679個の【金利・原油・ダウ・出来高】時系列データ。

4個の説明変数【金利・原油・ダウ・出来高】を表す。

y_tarin(679,)は[0 ore1]の答え。

X_testとかtestは同様のデータ(テスト用:3割に分割されたデータ)。

重要なのは、予測値(predict)。これがモデルで作成した明日の株価の上下予測である。👇


# 正解率(accuracy)、適合率(precision)、再現率(recall)を表示
 
print('\033[1m'+"\nモデルの正解率 全てのサンプルの正解率 (TP+TN/(TP+TN+FP+FN))--------------------------------------------------\n" + '\033[0m', accuracy_score(y_test, predict) , "\n\n適合率 真陽性/陽性の判定(真陽性+偽陽性)(TP/(TP+FP))\n",precision_score(y_test, predict),"\n\n再現率 真陽性/全ての陽性(真陽性+偽陰性)(TP/(TP+FN))\n", recall_score(y_test, predict))
 
print("\n教師データを使った正解率--------------------------------------------------\n",clf.score(X_train, y_train))
 
print("\nテストデータを使った正解率--------------------------------------------------\n",clf.score(X_test, y_test))
 

 

実行結果👇

黄色い線の正解率が予測と正解(教師データ)のマッチング率である。

再現率も大事だよ🙉


# 分類問題の評価基準であるprecision(適合率)、recall(再現率)、f1-score(F値)、support(実際のサンプル数)を出力。
 
import numpy as np
 
from sklearn.metrics import classification_report
 
print("\n評価基準--------------------------------------------------\n",classification_report(y_test, predict,target_names=['0 or price down', '1 or price up']))
 

 
# 平均二乗誤差を出力。
 
from sklearn.metrics import mean_squared_error
 
print("\n平均二乗誤差--------------------------------------------------\n",np.sqrt(mean_squared_error(y_test, predict)))
 

 
# 混同行列を生成: confusion_matrix()
 
from sklearn.metrics import confusion_matrix
 
import seaborn as sns
 
import matplotlib.pyplot as plt
 

 
y_true = y_test
 
y_pred = predict
 

 
cm = confusion_matrix(y_true, y_pred)
 

 
print("\n混同行列--------------------------------------------------\n", cm)
 
#グラフの箱サイズ
 
plt.figure(figsize=(4,2))
 
sns.heatmap(cm, annot=True, cmap='Blues')
 
plt.savefig('sklearn_confusion_matrix.png')
 

 
# https://qiita.com/0NE_shoT_/items/b702ab482466df6e5569
 
# FPR(偽陽性率)、TPR(真陽性率)、閾値。
 
from sklearn.metrics import roc_curve, auc
 

 
Y_score = clf.predict_proba(X_test)[:, 1] # 検証データが陽性(クラス1)に属する確率
 
fpr, tpr, thresholds = roc_curve(y_true=y_test, y_score=Y_score)
 
#グラフの箱サイズ
 
plt.figure(figsize=(8,6))
 
plt.plot(fpr, tpr, label='roc curve (area = %0.3f)' % auc(fpr, tpr))
 
plt.plot([0, 1], [0, 1], linestyle='--', label='random')
 
plt.plot([0, 0, 1], [0, 1, 1], linestyle='--', label='ideal')
 
plt.legend()
 
plt.xlabel('FPR=false positive rate')
 
plt.ylabel('TPR=true positive rate')
 
plt.show()

実行結果👇

precision = 適合率

recall = 再現率

F1スコア、support = 個数

混同行列

左上 TN(真陰性)、右上 FP(偽陽性)、左下 FN(偽陰性)、右下 TP(真陽性)

Python 1年生 体験してわかる!会話でまなべる!プログラミングのしくみ Kindle版¥1,960-

➎ python一括コード

コードです(*^-^*)

#@title 多層パーセプトロンで株価予測
 
import datetime
 
import yfinance as yf
 
import matplotlib.pyplot as plt
 
import seaborn as sns
 
from pandas_datareader import data as pdr
 
%matplotlib inline
 
import warnings
 
warnings.filterwarnings('ignore')
 
import mplfinance as mpf
 
import requests
 
import argparse
 

 
#スタート日を決める
 
start = "2020-1-1" #@param {type:"string"}
 

 
#①株価を取得する
 
start = start #株価を取得するスタート日を決める
 
end = datetime.date.today() #現在までの営業日(今日 =today)を取得する最終日とする
 
codelist = ["^DJI","^N225","^FTSE","000001.SS","IMOEX.ME","^BSESN","^BVSP", "BTC-USD","^TNX","GC=F","CL=F"]
 
#コードリストに取得したい銘柄を入れる アメリカ 日本 イギリス 中国 ロシア インド ブラジル ビットコ 10年金利 金 原油
 
yf.pdr_override() # <== that's all it takes :-)
 
# download dataframe
 
data2 = pdr.get_data_yahoo(codelist, start, end)["Adj Close"] .dropna()
 
data2.rename(columns={'^DJI':'ダウ',
 
'^N225':'日経平均',
 
'^FTSE':'イギリス',
 
"000001.SS":'中国',
 
'IMOEX.ME':'ロシア',
 
'^BSESN':'インド',
 
'^BVSP':'ブラジル',
 
'BTC-USD':'ビットコ',
 
'^TNX':'10 Year Treasury',
 
"GC=F":"金",
 
"CL=F":"原油"},inplace=True)
 

 
# 前処理開始。分析用のXとyを作成。
 
from sklearn.model_selection import train_test_split
 
from sklearn.metrics import accuracy_score, precision_score, recall_score
 
from sklearn.linear_model import LogisticRegression
 
from sklearn.neural_network import MLPClassifier
 
from sklearn.pipeline import make_pipeline
 
from sklearn.preprocessing import StandardScaler
 

 
ticker = "MSFT" #@param {type:"string"}
 
yf.pdr_override()
 
df = pdr.get_data_yahoo(ticker, start, end)
 

 
# data2から説明変数追加
 
df["金利"] = data2['10 Year Treasury']
 
df["原油"] = data2['原油']
 
df["ダウ"] = data2['ダウ']
 
# 前日との差分をDiffへ格納
 
df["Diff"] = df["Adj Close"].diff()
 

 
# 終値×出来高を"出来高"へ格納
 
df["出来高"] = df["Adj Close"] * df["Volume"]
 
# 差分[Diff]を1行、上にずらして(.shift(-1))、xが0より大きい(つまり値上がりしていれば1。)
 
# xが0より大きくない(つまり値下がりしていれば0。)のラムダ式xを作成。.apply()でラムダ式をdf[Diff]へ格納して、df[y]を作成。
 
# yは未来の値。yが1なら明日の株価終値は上昇。つまりyは正解ラベル。
 
df["y"] = df["Diff"].apply(lambda x: 1 if x > 0 else 0).shift(-1)
 
# OpenとかHighとかをdfから削除.drop(["消すindex"],axis=1で列を指定)。.dropna()で欠損値のある行を削除。
 
df2 = df.drop(["Open", "High", "Low", "Close", "Volume", "Diff", "Adj Close"],axis=1,).dropna()
 
# print('\033[35m'+"dfを表示\n"+'\033[0m', (df))
 
# print('\033[35m'+"df2を表示\n"+'\033[0m', (df2))
 

 
# 説明変数
 
# yを列ごと削除してXを作成。
 
X = df2.drop(["y"], axis=1)
 
# 目的変数
 
# dfのyの値をyへ格納。yは正解ラベル。つまり(値下がりと値上がりの[0,1])だけのデータをyに充当。
 
y = df2["y"]
 

 
# デフォルトはtest_size=0.25で25%がテスト用、残りの75%が訓練用。ここでは、テスト用を30%に設定。
 
# デフォルトでは要素がシャッフルされて分割される。引数shuffle=Falseとするとシャッフルされずに先頭から順番に分割される。
 
# 機械学習のモデルの性能を比較するような場合、どのように分割されるかによって結果が異なってしまうため、乱数シードを固定して常に同じように分割されるようにする必要がある。
 
# ここでは使用していないが、要素がシャッフルされる場合、デフォルトでは実行するたびにランダムに分割される。引数random_stateを指定して乱数シードを固定すると常に同じように分割される。
 
# https://note.nkmk.me/python-sklearn-train-test-split/
 
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3,shuffle=False,)
 

 
# モデルに多層パーセプトロンを適用
 
clf = make_pipeline(StandardScaler(), MLPClassifier(random_state=0, shuffle=False))
 
clf.fit(X_train,y_train)
 

 
print("\nX_train.shape", X_train.shape)
 
print("\ny_train.shape", y_train.shape)
 
print("\nX_test.shape", X_test.shape)
 
print("\ny_test.shape", y_test.shape)
 
print("\n学習用の説明変数 X_train -------------------------\n", X_train)
 
print("\n学習用の目的変数 y_train -------------------------\n", y_train)
 
print("\n評価用の説明変数 X_test -------------------------\n", X_test)
 
print("\n評価用の目的変数 y_test -------------------------\n", y_test)
 

 

 
# 学習させた内容を、テスト用データで確かめる。
 
predict = clf.predict(X_test)
 
print("\n予測値 predict --------------------------------------------------\n", predict)
 

 
# 正解率(accuracy)、適合率(precision)、再現率(recall)を表示
 
print('\033[1m'+"\nモデルの正解率 全てのサンプルの正解率 (TP+TN/(TP+TN+FP+FN))--------------------------------------------------\n" + '\033[0m', accuracy_score(y_test, predict) , "\n\n適合率 真陽性/陽性の判定(真陽性+偽陽性)(TP/(TP+FP))\n",precision_score(y_test, predict),"\n\n再現率 真陽性/全ての陽性(真陽性+偽陰性)(TP/(TP+FN))\n", recall_score(y_test, predict))
 
print("\n教師データを使った正解率--------------------------------------------------\n",clf.score(X_train, y_train))
 
print("\nテストデータを使った正解率--------------------------------------------------\n",clf.score(X_test, y_test))
 

 
# 分類問題の評価基準であるprecision(適合率)、recall(再現率)、f1-score(F値)、support(実際のサンプル数)を出力。
 
import numpy as np
 
from sklearn.metrics import classification_report
 
print("\n評価基準--------------------------------------------------\n",classification_report(y_test, predict,target_names=['0 or price down', '1 or price up']))
 

 
# 平均二乗誤差を出力。
 
from sklearn.metrics import mean_squared_error
 
print("\n平均二乗誤差--------------------------------------------------\n",np.sqrt(mean_squared_error(y_test, predict)))
 

 
# tickerの株価をプロット
 
plt.figure(figsize=(6,4))
 
chart = yf.download(ticker, start=start, end=end)
 
mpf.plot(chart,type='candle',mav=(5,25,60),volume=True,show_nontrading=True)
 

 
# 混同行列を生成: confusion_matrix()
 
from sklearn.metrics import confusion_matrix
 
import seaborn as sns
 
import matplotlib.pyplot as plt
 

 
y_true = y_test
 
y_pred = predict
 

 
cm = confusion_matrix(y_true, y_pred)
 

 
print("\n混同行列--------------------------------------------------\n", cm)
 
#グラフの箱サイズ
 
plt.figure(figsize=(4,2))
 
sns.heatmap(cm, annot=True, cmap='Blues')
 
plt.savefig('sklearn_confusion_matrix.png')
 

 
# https://qiita.com/0NE_shoT_/items/b702ab482466df6e5569
 
# FPR(偽陽性率)、TPR(真陽性率)、閾値。
 
from sklearn.metrics import roc_curve, auc
 

 
Y_score = clf.predict_proba(X_test)[:, 1] # 検証データが陽性(クラス1)に属する確率
 
fpr, tpr, thresholds = roc_curve(y_true=y_test, y_score=Y_score)
 
#グラフの箱サイズ
 
plt.figure(figsize=(5,4))
 
plt.plot(fpr, tpr, label='roc curve (area = %0.3f)' % auc(fpr, tpr))
 
plt.plot([0, 1], [0, 1], linestyle='--', label='random')
 
plt.plot([0, 0, 1], [0, 1, 1], linestyle='--', label='ideal')
 
plt.legend()
 
plt.xlabel('FPR=false positive rate')
 
plt.ylabel('TPR=true positive rate')
 
plt.show()

如何でしたでしょうか❕❓

これであなたも機械学習の使い手です!!!(^_-)-☆

銘柄と期間、パラメータを弄繰り回して、素晴らしい予測モデルを発見できるかも❕❓

❻ Facebookが開発した機械学習ライブラリで株価を予測

を使って、バンク・オブ・アメリカの今後の株価を予測して見た。

・対象銘柄:バンク・オブ・アメリカ【BAC】

・学習期間:2016.6.14~2021.6.13(5年間)

現在(2021.6.14時点)の株価が41.86ドルなのに対して、1年後は60ドル付近まで上昇する予測ですね(・ω・)ノ

ホンマけ~~?❓

では、ばいちゃ(・ω・)ノ

pythonでプログラミングがしたい!!
 
pythonを学びたい!という方には、
 
オンラインプログラミング教室『Aidemy アイデミー』がお勧めです。
 
ご自身でプログラム環境を用意する必要は無く、サイトへアクセスするだけです。 創業者は東京大学工学部卒の石川聡彦さん。
 
著書に『人工知能プログラミングのための数学がわかる本』(KADOKAWA/2018年)など。
 
無料で、お試しもできますので安心です。
 
お時間ある方は下記リンクを覗いてみてはいかがでしょうか(*'ω'*)

    12740
    4