機械学習で株価を予測することに挑戦していきます。今回は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で株価予測②:特徴量選択とデータの標準化、正規化~