#目的
1. githubにコードが上がっているので、どのモデルが一番いいのか教えて欲しい
2. pythonを使用して、株価が次の日上がるか下がるか機械学習させて結果を表示
- 開発環境:python3
- githubのコードURL:https://github.com/maeda-naoya-fk/Machine-Learning-for-stock
#準備
-
本記事はわかりやすいようにjupyterベース(Example.ipynb)でコードを回していきます。jupyterない人も大丈夫! config.iniをいじってコマンドで
python3 main.py
と打てばok -
コードの中身を詳しく説明しても長ったらしくなるので、簡単に何をしたか説明します
from datetime import datetime
from scraiping import Scraiping
from complete import Complete
from train import Tree_updown, Tree_updown_k
start = datetime(2010, 1, 1)
finish = datetime(2020, 5, 17)
target_number = '4751' #(株)サイバーエージェント
prepare_number = ['1309', #上海株式指数・上証50連動型上場投資信託
'1325', #(NEXT FUNDS)ブラジル株式指数上場投信
'1326', #SPDRゴールド・シェア
'1377', #サカタのタネ
'1465', #ダイワ上場投信-JPX日経400インバース
'1633', #(NEXT FUNDS)不動産上場投信
'1678', #(NEXT FUNDS)インド株式指数上場投信
'1698', #上場インデックスファンド日本高配当
]
headers = {'User-Agent' : 'Please write your User-Agent'}
max_depth = 5
test_size = 0.25
k = 2
-
各モジュールのimport、いつからいつまでのデータをとるか、目的変数(4751)、説明変数(1309, 1325, 1326...)をセットアップしています。
-
headersはこのサイトみてgetしてみてください。<'https://note.nkmk.me/python-beautiful-soup-scraping-yahoo/'> (ちなみになくても大丈夫かも。詳しくはわからないです。)
-
max_depth:機械学習をする際にどのくらいの階層まで掘り下げるか
-
test_size:テスト用と学習用でどのくらいの比率で分けるか
-
k:株価の次の日の値が上下何%で変動するか
#スクレイピング
使用するwebサイト:株式投資メモ
- スクレイピングで株価の情報をとってきます。
stock_numbers = prepare_number.copy()
stock_numbers.insert(0, target_number)
dfs = Scraiping(stock_numbers, start, finish, headers).main()
- scraping.pyのモジュールに引数をぶちこんでます。
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
class Scraiping:
def __init__(self, stock_numbers, start, finish, headers):
self.sns = stock_numbers
self.start = start
self.finish = finish
self.headers = headers
def main(self):
dfs = []
for sn in self.sns:
df = self.scra(sn)
dfs.append(df)
print('Done : ' + sn)
return dfs
def scra(self, sn):
data = []
for y in range(self.start.year, self.finish.year+1):
url = 'https://kabuoji3.com/stock/{}/{}/'.format(int(sn), y)
soup = BeautifulSoup(requests.get(url, headers = self.headers).content,'html.parser')
tr = soup.find_all('tr')
t = 1
while True:
try:
td_t = [t.text for t in tr[t].find_all('td')]
date = pd.to_datetime(td_t[0])
if (self.start <= date) and (date <= self.finish):
td_t[4] = int(td_t[4])
data.append(td_t)
elif (date > self.finish):
break
except IndexError:
break
t += 1
time.sleep(1)
df = pd.DataFrame(data, columns = ['日付', '始値', '高値', '安値', '終値', '出来高', '終値調整'])
return df
#機械学習のための前準備
- 学習させるために前準備をします。とってきたデータをそのまま説明変数にしても意味がないので前日比を出していきます。(※とても重要)
complete_df = Complete(dfs, stock_numbers).com()
- complete.pyのモジュールに先ほど作成したdfsを引数にぶちこんでます。
- 終値をつかって
(次の日)ー(前日)/(前日)
をして全てのデータを結合しています。
import pandas as pd
import sys
class Complete:
def __init__(self, dfs, stock_numbers):
self.dfs = dfs
self.sns = stock_numbers
def com(self):
for i in range(len(self.dfs)):
df = self.dfs[i][['日付', '終値']]
num = self.sns[i]
df = df.rename(columns = {'日付':'Date', '終値':num})
df[num + '_Diff'] = df[num]/df[num].shift()-1
if i == 0:
complete_df = df
else:
complete_df = pd.merge(complete_df, df, on = 'Date')
columns = self.sns.copy()
columns.insert(0, 'Date')
complete_isna = complete_df[columns]
if complete_isna.isna().sum().sum() == 0:
return complete_df
else:
print('Error : There are missing value > Please choose other target_number or prepare_number')
self.isna(complete_isna)
def isna(self, complete_isna):
sys.exit()
ちなみに今回は(いろいろ試したが)欠損値が見つからなかったので、欠損値処理を無視しています。もし欠損値があったら適宜コード改善していこーと!
#機械学習(決定木)とその結果
- ここから目的の機械学習をさせて次の日の予想をしていきます。
##単にupdown
- これは単に株価の終値が前日より上がったら1、下がったら-1として目的変数にいれていきます。
tu = Tree_updown(complete_df, stock_numbers, test_size, max_depth)
X, y = tu.prepare()
tu.predict(X, y)
- train.pyのモジュールにcomplete_dfやその他もろもろをぶち込んでいます。
- X, y は説明変数、目的変数となっています。
- そしてpredictで予想!
###感想###
次の日は下がると予想されました。
正解率はどちらも低くなっていますね...
っていうか、正解率がほぼ50%って笑笑 やった意味がないですね。
学習用正解率、テスト用正解率に差がなく、どちらも1.0に近ければいいモデルができていると思うので、みなさんも是非いろいろパラメータを変えていい結果が出たら教えてください。
説明変数がどれくらい目的変数に寄与しているかはcoefficientの列を見てもらえればわかります。
##2%updown(おまけ)
- 次に上下何%でupdownするかを考慮します(ここでは2%)
- 株価の終値が前日より2%上がったら1、下がったら-1、そうでなかったら0として目的変数にいれていきます
tu_k = Tree_updown_k(complete_df, stock_numbers, test_size, max_depth, k)
X, y = tu_k.prepare_k()
tu_k.predict(X, y)
###感想###
正解率が上がっているのはconstantの数が多くなっているからですね。
本当に欲しい結果としては、投資する時にupかdownの情報だと思うので、あまりこの結果は意味のないような気がするが、勉強にはなりました。
- 一応train.pyも載せておきます。
from sklearn.tree import DecisionTreeClassifier
import sklearn.model_selection
import pandas as pd
class Tree_updown:
def __init__(self, complete_df, stock_numbers, test_size, max_depth):
self.c_df = complete_df
self.sns = stock_numbers
self.ts = test_size
self.m = max_depth
self.diffs = [sn + '_Diff' for sn in self.sns]
def prepare(self):
y = self.c_df[self.sns[0]].shift(-1) - self.c_df[self.sns[0]]
y.loc[y >= 0] = 1
y.loc[y < 0] = -1
y = y[1:-1]
X = self.c_df[self.diffs].iloc[1:-1]
return X, y
def predict(self, X, y):
X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(X, y, test_size = self.ts, train_size = 1 - self.ts, random_state = 0)
model = DecisionTreeClassifier(random_state = 0, max_depth = self.m)
model.fit(X_train, y_train)
next_day_diff = self.c_df[self.diffs].iloc[-1]
next_day_predict = model.predict([next_day_diff])
print('predict next day : UP') if next_day_predict == 1 else print('predict next day : CONSTANT') if next_day_predict == 0 else print('predict next day : DOWN')
print('')
print('テスト用正解率:{}'.format(model.score(X_test, y_test)))
print('学習用正解率:{}'.format(model.score(X_train, y_train)))
importance = pd.DataFrame({'feature_names':self.sns, 'coefficient':model.feature_importances_})
print('')
print(importance)
print('')
print('データ数:{}'.format(len(y)))
class Tree_updown_k(Tree_updown):
def __init__(self, complete_df, stock_numbers, test_size, max_depth, k):
super().__init__(complete_df, stock_numbers, test_size, max_depth)
self.k = k
def prepare_k(self):
y = self.c_df[self.sns[0]].shift(-1)/self.c_df[self.sns[0]] - 1
y.loc[y*100 >= self.k] = 1
y.loc[y*100 <= -self.k] = -1
y.loc[(-self.k < y*100) & (y*100 < self.k)] = 0
y = y[1:-1]
X = self.c_df[self.diffs].iloc[1:-1]
return X, y
class Verify(Tree_updown_k):
def __init__(self, complete_df, stock_numbers, verify_df, test_size, max_depth, k):
super().__init__(complete_df, stock_numbers, test_size, max_depth, k)
self.verify_df = verify_df
def verify(self, X, y):
X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(X, y, test_size = self.ts, train_size = 1 - self.ts, random_state = 0)
model = DecisionTreeClassifier(random_state = 0, max_depth = self.m)
model.fit(X_train, y_train)
y_test = self.verify_df[self.sns[0]].shift(-1)/self.verify_df[self.sns[0]] - 1
y_test.loc[y_test*100 >= self.k] = 1
y_test.loc[y_test*100 <= -self.k] = -1
y_test.loc[(-self.k < y_test*100) & (y_test*100 < self.k)] = 0
y_test = y_test[1:-1]
X_test = self.verify_df[self.diffs][1:-1]
next_day_predict = model.predict(X_test)
print(next_day_predict)
print(y_test)
print(next_day_predict == y_test)
#まとめ
- 簡単にお金稼ぎなんてできないのかー
- いいモデルを皆さん探してみてください。そして教えてください。
株価予測のための機械学習