機械学習で株価を予測することに挑戦していきます。前回に引き続き、scikit-learnで過去の株価データを基に学習し、株価予測を行います。今回は特徴量選択とデータの標準化、正規化を実践します。
関連記事
機械学習で株価予測~scikit-learnで株価予測③:特徴量の重要度を可視化し、ワンホットエンコーディング、ビニング、交互作用特徴量、多項式特徴量を試す~
機械学習で株価予測~scikit-learnで株価予測④:世界の主要指数の追加~
環境
- OS:Windows10
- Python:3.6.5
- sklearn:0.19.1
概要
目標
様々なデータ(経済指標、為替レート、ダウ平均等)に基づいて、翌日の株価日足が陽線/陰線のどちらかになるのかを予測(分類)するモデルを作成することを目標とします。
予測対象銘柄
日経225連動型上場投資信託
使用する機械学習ライブラリと学習手法
- 使用ライブラリ:scikit-learn
- アルゴリズム:線形SVM(線形サポートベクターマシーン)
- 学習手法:教師あり学習
使用データ
株式投資メモ・株価データベース(https://kabuoji3.com)様に掲載されている過去の株価データを使用させていただいています。
実装
今回は以下のコードで2001~2018年の株価データを全て連結し、学習を行っています。
# Pandas、globのimport import pandas as pd import glob # 2001~2018年の株価データをマージする # globでファイル名の一覧を取得 stock_price_files = glob.glob('stockPrice/*.csv') stock_price_list = [] # ファイルを読み込み、DataFrameでlistに格納する。 for f in stock_price_files: stock_price_list.append(pd.read_csv(f, header=1, encoding="shift-jis")) # Listに格納されたデータを全てconcat関数で連結 stock_price_all = pd.concat(stock_price_list) stock_price_all.to_csv("stock_price.csv",index = False, encoding="shift-jis")
前日までのデータから、翌日の株価が上がるか下がるかを判断するモデルとしています。まずは日付以外の全ての特徴量を使用してみましたが、テストデータへの正解率が50%以下のいまいちな精度です。そこで使用する特徴量を評価し、使用する特徴量を絞り込むことで精度が上がるか試していきます。
特徴選択
以下の3つの代表的な手法をそれぞれ使用して、特徴量を評価していきます。
単変量統計
特徴量をある指標の基にランキング付けし、そのランキングの中から上位i個を採用する手法です。sklearn.feature_selection.SelectKBestで実装することが出来ます。今回は以下2つの評価関数をそれぞれ実行し、結果を見てみます。
- f_classif(デフォルト):F検定によって順位付けを行う
- mutual_info_classif:相互情報量に基づいてランキングをつける
from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import mutual_info_classif # 単変量統計による特徴量選択 for i in range(1, 6): # 上位i個の特徴量を取得する。(評価関数 = f_classif) selector = SelectKBest(k=i) selector.fit(X_train , y_train) # 各特徴量を選択したか否かのmaskを取得 mask = selector.get_support() print('上位' + str(i) + '個の特徴量を選択') print('始値', '高値', '安値', '終値', '出来高', '終値調整値') print(mask) 上位1個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False False False False False True] 上位2個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False False False True False True] 上位3個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False False True True False True] 上位4個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [ False True True True False True] 上位5個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [ False True True True True True] # 単変量統計による特徴量選択 for i in range(1, 6): # 上位i個の特徴量を取得する。(評価関数 = mutual_info_classif) selector = SelectKBest(score_func = mutual_info_classif, k=i) selector.fit(X_train , y_train) # 各特徴量を選択したか否かのmaskを取得 mask = selector.get_support() print('上位' + str(i) + '個の特徴量を選択') print('始値', '高値', '安値', '終値', '出来高', '終値調整値') print(mask) 上位1個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False True False False False False] 上位2個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False True False False False True] 上位3個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False True False True False True] 上位4個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False True True True False True] 上位5個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False True True True True True]
選択した特徴量はboolean配列として取得することが出来ます。結果を見ると、ランキングに違いがあることがわかります。
評価関数 = f_classifの場合のランキング
- 終値調整値
- 終値
- 安値
- 高値
- 出来高
- 始値
評価関数 = mutual_info_classifの場合のランキング
- 高値
- 終値調整値
- 終値
- 安値
- 出来高
- 始値
f_classifの場合は終値が上位に来ていますが、mutual_info_classifの場合はf_classifで下位にランキングされている高値が上位にきており、ランキングの傾向が異なることがわかります。
モデルベース特徴量選択
機械学習アルゴリズムの中で変数選択も同時に行ってくれる手法。教師あり学習モデルを1つ用いてここの特徴量の重要性を判断し、重要なものだけを残してくれます。特徴量抽出に使用するモデルは構築しているモデルと同じである必要はありません。今回はRandomForestで特徴量の重要度を選択してみます。
# モデルベース特徴量選択による特徴量選択 # estimatorとしてRandomForestClassifierを使用。重要度がmedian(中央値)以上のものを選択 selector = SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=1), threshold="median") selector.fit(X_train , y_train) mask = selector.get_support() print('始値', '高値', '安値', '終値', '出来高', '終値調整値') print(mask) 始値 高値 安値 終値 出来高 終値調整値 [ True True False False True False]
始値、高値、出来高の3つが選択されました。単変量統計と異なる傾向の特徴量が選択されていることがわかります。
反復特徴量選択
まったく特徴量を使わないところから、ある基準が満たされるまで1つずつ重要度が高い特徴量を加えていく、もしくは、全ての特徴量を使う状態から1つずつ特徴量を取り除いていくという操作を繰り返すことで特徴量を選択する手法。今回はRFE(Recursive Feature Elimination; 再帰的特徴量削減)で、全ての特徴量を含んだモデルから開始し、指定した数になるまで重要性の最も低い特徴量を削減していく手法を使ってみます。
# REFによる特徴量選択 # estimatorとしてRandomForestClassifierを使用 for i in range(1, 6): selector = RFE(RandomForestClassifier(n_estimators=100, random_state=1), n_features_to_select=i) selector.fit(X_train , y_train) # 各特徴量を選択したか否かのmaskを取得 mask = selector.get_support() print('上位' + str(i) + '個の特徴量を選択') print('始値', '高値', '安値', '終値', '出来高', '終値調整値') print(mask) 上位1個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [False False False False True False] 上位2個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [ True False False False True False] 上位3個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [ True False False False True True] 上位4個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [ True False True False True True] 上位5個の特徴量を選択 始値 高値 安値 終値 出来高 終値調整値 [ True True True False True True]
- 出来高
- 始値
- 終値調整値
- 安値
- 高値
- 終値
上記のようにランキング付けされました。出来高、始値はこの手法でも上位にランク付けされていることがわかります。
抽出した特徴量でモデルの再作成
単変量統計以外は選択された特徴量に同じような傾向が見えた為、以下4つの変数に絞り込み再度学習を行いました。
- 始値
- 高値
- 出来高
- 終値調整値
結果は以下の通りで、精度が全く変わりませんでした。どうやら特徴量選択に問題があるわけではないようです。
# 正解率の計算 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) + "%") トレーニングデータに対する正解率:51.76224611708483% テストデータに対する正解率:48.21002386634845%
データの標準化、正規化
特徴量の尺度を揃えるため、データの標準化や正規化を行う場合があります。今回使用しているデータは太宗が株価を表していますが、出来高のように数値の意味する物が異なる特徴量も存在する為、正規化と標準化を試してみます。
標準化
from sklearn.preprocessing import StandardScaler # データの標準化 sc = StandardScaler() sc.fit(successive_data) successive_data = sc.transform(successive_data)
上記のコードを追加し、データを標準化したうえで再度学習をし、精度を測定します。標準化は、平均0, 標準偏差1に変換されています。
# 正解率の計算 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) + "%") トレーニングデータに対する正解率:51.37395459976105% テストデータに対する正解率:47.13603818615752%
標準化によって精度を改善することを期待しましたが、改善することは出来ません。
正規化
from sklearn.preprocessing import MinMaxScaler # データの正規化 ms = MinMaxScaler() ms.fit(successive_data) successive_data = ms.transform(successive_data)
上記コードを追加し、正規化を実施。変換後のデータの最小値, 最大値を0, 1へ変換しています。
# 正解率の計算 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) + "%") トレーニングデータに対する正解率:51.16487455197133% テストデータに対する正解率:47.61336515513126%
正規化に関しても特に精度を改善することはできませんでした。
まとめ
今回は特徴量選択とデータの標準化、正規化を実施しました。前回のモデルより若干精度は上がってはいますが、まだ意味のあるモデルとは言えない精度となっています。次回は株価データ以外も特徴量として用い、精度の改善に挑戦していきます。
記事執筆終了地点のソースコード
参考書籍
オライリーから出版されているの「Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎」の内容を参考にしています。機械学習に必要な基礎知識が網羅的に記載されており、これから機械学習を始めようと思っている方にはとてもおすすめです。