機械学習で株価予測~scikit-learnで株価予測①~

機械学習で株価予測~scikit-learnで株価予測①~
この記事は最終更新から5年以上経過しています。内容が古くなっている可能性があります。

機械学習で株価を予測することに挑戦していきます。今回はscikit-learnで過去の株価データを基に学習し、株価予測を行います。

関連記事

機械学習で株価予測~scikit-learnで株価予測②:特徴量選択とデータの標準化、正規化~

機械学習で株価予測~scikit-learnで株価予測③:特徴量の重要度を可視化し、ワンホットエンコーディング、ビニング、交互作用特徴量、多項式特徴量を試す~

機械学習で株価予測~scikit-learnで株価予測④:世界の主要指数の追加~

環境

  • OS:Windows10
  • Python:3.6.5
  • sklearn:0.19.1

概要

目標

様々なデータ(経済指標、為替レート、ダウ平均等)に基づいて、翌日の株価日足が陽線/陰線のどちらかになるのかを予測するモデルを作成することを目標とします。

予測対象銘柄

日経225連動型上場投資信託

使用する機械学習ライブラリ

この記事ではscikit-learnを用いた株価予測について記載します。使用する分類アルゴリズムは線形サポートベクターマシーンで、学習手法は教師あり学習です。

使用データ

株式投資メモ・株価データベース(https://kabuoji3.com)様に掲載されている過去の株価データを使用させていただいています。

実装

ソースコード

# サポートベクターマシーンのimport
from sklearn import svm
# train_test_splitのimport
from sklearn.model_selection import train_test_split
# accuracy_scoreのimport
from sklearn.metrics import accuracy_score
# Pandasのimport
import pandas as pd

# 株価データの読み込み
stock_data = pd.read_csv("stock_price.csv", encoding="shift-jis")
print(stock_data)
始値     高値     安値     終値     出来高  終値調整値
0    19790  20100  19780  20080  749647  20080
1    20100  20120  19960  20020  679991  20020
2    19850  19980  19830  19950  474555  19950
3    19910  19980  19750  19820  388580  19820
4    19860  19890  19830  19860  351023  19860
5    19760  19780  19560  19640  591801  19640
6    19660  19790  19650  19790  372166  19790
7    19710  19740  19550  19610  481413  19610
8    19560  19560  19310  19320  658995  19320
9    19240  19430  19130  19400  689105  19400
10   19550  19620  19470  19580  308724  19580
11   19540  19680  19530  19630  335402  19630
12   19450  19520  19360  19400  437368  19400
13   19290  19400  19260  19290  399512  19290
14   19570  19630  19460  19510  871864  19510
15   19740  19900  19720  19870  430065  19870
16   19960  19980  19890  19930  406369  19930
17   19850  19880  19790  19860  200917  19860
18   19610  19680  19520  19540  572642  19540
19   19420  19640  19400  19640  469320  19640
20   19660  19660  19350  19410  641040  19410
21   19500  19550  19310  19400  463324  19400
22   19580  19590  19390  19450  269708  19450
23   19320  19460  19290  19400  234788  19400
24   19420  19490  19350  19470  130284  19470
25   19430  19470  19350  19390  126467  19390
26   19730  19890  19690  19860  582789  19860
27   20000  20020  19910  19960  475382  19960
28   19980  19990  19720  19740  385408  19740
29   19960  19990  19920  19920  553083  19920
..     ...    ...    ...    ...     ...    ...
216  23230  23370  22920  23010  722737  23010
217  22910  23020  22810  22860  274519  22860
218  23070  23170  23020  23040  211336  23040
219  23240  23290  23120  23140  189782  23140
220  23010  23170  22970  23140  238035  23140
221  23260  23270  23020  23100  233737  23100
222  23060  23190  22960  23090  140929  23090
223  23230  23250  23140  23200  285786  23200
224  23200  23360  23120  23350  279160  23350
225  23550  23610  23280  23440  358644  23440
226  23460  23470  23300  23330  249497  23330
227  23200  23280  23120  23220  152349  23220
228  23140  23140  22700  22770  515197  22770
229  22950  23120  22910  23090  182727  23090
230  23210  23430  23150  23430  501133  23430
231  23500  23550  23390  23550  230348  23550
232  23540  23600  23440  23490  267555  23490
233  23500  23500  23290  23360  224779  23360
234  23330  23390  23240  23300  191331  23300
235  23220  23360  23080  23160  254955  23160
236  23370  23530  23340  23520  314500  23520
237  23570  23610  23470  23480  193207  23480
238  23440  23540  23410  23500  140023  23500
239  23460  23500  23330  23470  189583  23470
240  23440  23510  23410  23480  150986  23480
241  23500  23550  23470  23540   67464  23540
242  23530  23540  23470  23490  112306  23490
243  23510  23570  23500  23530  132280  23530
244  23550  23590  23360  23390  174425  23390
245  23480  23510  23370  23410  231315  23410

[246 rows x 6 columns]

# 要素数の設定
count_s = len(stock_data)

# 株価の上昇率を算出、おおよそ-1.0~1.0の範囲に収まるように調整
modified_data = []
for i in range(1,count_s):
    modified_data.append(float(stock_data.loc[i,['終値']] - stock_data.loc[i-1,['終値']])/float(stock_data.loc[i-1,['終値']])*20)
# 要素数の設定
count_m = len(modified_data)

# 過去4日分の上昇率のデータを格納するリスト
successive_data = []

# 正解値を格納するリスト 価格上昇: 1 価格低下:0
answers = []

#  連続の上昇率のデータを格納していく
for i in range(4, count_m):
    successive_data.append([modified_data[i-4],modified_data[i-3],modified_data[i-2],modified_data[i-1]])
    # 上昇率が0以上なら1、そうでないなら0を格納
    if modified_data[i] > 0:
        answers.append(1)
    else:
        answers.append(0)

# データの分割(データの80%を訓練用に、20%をテスト用に分割する)
X_train, X_test, y_train, y_test =train_test_split(successive_data, answers, train_size=0.8,test_size=0.2,random_state=1)

# サポートベクターマシーン
clf = svm.LinearSVC()
# サポートベクターマシーンによる訓練
clf.fit(X_train , y_train)

# 学習後のモデルによるテスト
# トレーニングデータを用いた予測
y_train_pred = clf.predict(X_train)
# テストデータを用いた予測
y_val_pred = clf.predict(X_test)

# 正解率の計算
train_score = accuracy_score(y_train, y_train_pred)
test_score = accuracy_score(y_test, y_val_pred)

# 正解率を表示
print("トレーニングデータに対する正解率:" + str(train_score * 100) + "%")
print("テストデータに対する正解率:" + str(test_score * 100) + "%")

トレーニングデータに対する正解率:58.333333333333336%
テストデータに対する正解率:40.816326530612244%

株価データには2017年(246日分)の株価データの終値を用いています。終値の値を比べて前日と比較した株価の上昇率データと正解データを作成し、80%のデータを用いて訓練を行っています。御覧の通り、これだけではトレーニングデータに対する正解率が約58%、テストデータに対する正解率が約41%という、意味のないモデルとなってしまっています。

教師データを増やしてみる

246日分では学習量が不足しているのかもしれないため、教師データを増やしていき、正解率に変化が出るか試してみます。

2016~2017年分

# 正解率を表示
print("トレーニングデータに対する正解率:" + str(train_score * 100) + "%")
print("テストデータに対する正解率:" + str(test_score * 100) + "%")

トレーニングデータに対する正解率:55.297157622739014%
テストデータに対する正解率:54.63917525773196%

トレーニングデータに対する正解率が下がってしまいましたが、念のためもう少し増やしながら傾向を見ていきます。

2015~2017年分

# 正解率を表示
print("トレーニングデータに対する正解率:" + str(train_score * 100) + "%")
print("テストデータに対する正解率:" + str(test_score * 100) + "%")

トレーニングデータに対する正解率:53.608247422680414%
テストデータに対する正解率:43.83561643835616%

2014~2017年分

# 正解率を表示
print("トレーニングデータに対する正解率:" + str(train_score * 100) + "%")
print("テストデータに対する正解率:" + str(test_score * 100) + "%")

トレーニングデータに対する正解率:53.79665379665379%
テストデータに対する正解率:53.333333333333336%

2013~2017年分

# 正解率を表示
print("トレーニングデータに対する正解率:" + str(train_score * 100) + "%")
print("テストデータに対する正解率:" + str(test_score * 100) + "%")

トレーニングデータに対する正解率:52.92908530318602%
テストデータに対する正解率:54.09836065573771%

徐々に訓練データの量を増やしてみましたが、あまり正解率は向上しません。単純に訓練データが多ければ精度が上がる、という訳ではないことがわかります。

パラメーターの最適化

scikit learnにはグリッドサーチという機械学習モデルのハイパーパラメータを自動的に最適化してくれる機能がある為、パラメーターを最適化してみます。

# グリッドサーチのimport
from sklearn.model_selection import GridSearchCV

# グリッドサーチするパラメータを設定
parameters = {'C':[1, 3, 5],'loss':('hinge', 'squared_hinge')}

# グリッドサーチを実行
clf = GridSearchCV(svm.LinearSVC(), parameters)
clf.fit(X_train, y_train) 

# グリッドサーチ結果(最適パラメータ)を取得
GS_C, GS_loss = clf.best_params_.values()
print ("最適パラメータ:{}".format(clf.best_params_))

最適パラメータ:{'C': 3, 'loss': 'hinge'}

# 最適パラメーターを指定して再度学習
clf = svm.LinearSVC(loss=GS_loss, C=GS_C)
clf.fit(X_train , y_train)

# 再学習後のモデルによるテスト
# トレーニングデータを用いた予測
y_train_pred = clf.predict(X_train)
# テストデータを用いた予測
y_val_pred = clf.predict(X_test)

# 正解率の計算
train_score = accuracy_score(y_train, y_train_pred)
test_score = accuracy_score(y_test, y_val_pred)
# 正解率を表示
print("トレーニングデータに対する正解率:" + str(train_score * 100) + "%")
print("テストデータに対する正解率:" + str(test_score * 100) + "%")

トレーニングデータに対する正解率:60.416666666666664%
テストデータに対する正解率:42.857142857142854%

今回は正則化項(C)と損失関数の調整を行いました。デフォルトでは{‘C’: 1, ‘loss’: ‘squared_hinge’}と設定されていますが、最適化パラメーターは{‘C’: 3, ‘loss’: ‘hinge’}と異なる設定値が指定されていることがわかります。そこで、最適パラメーターを指定して2017年の株価データを用いて再度学習させると、トレーニングデータに対する正解率が約60%、テストデータに対する正解率が約43%となり、最初に比べて精度が向上したことがわかります。

まとめ

scikit-learnを用いた簡単な株価学習を実践しましたが、これだけでは精度の良いモデルは構築できないことがわかりました。

モデルの精度を上げていくため、次回以降は教師データのバリエーションやデータの前処理、また他の分類アルゴリズムも試して精度を上げることに挑戦していきます。

  • 次の記事

機械学習で株価予測~scikit-learnで株価予測②:特徴量選択とデータの標準化、正規化~

参考書籍

scikit-learnカテゴリの最新記事


Warning: Use of undefined constant XML - assumed 'XML' (this will throw an Error in a future version of PHP) in /home/kkmax/kkmax-develop.com/public_html/wp-content/plugins/wp-syntaxhighlighter/wp-syntaxhighlighter.php on line 1048