<基礎学習>機械学習(ランダムフォレスト)でFX - 為替データの特徴量抽出
もくじ
- 近況報告
- ランダムフォレストでFX分析してみた
- 感想など
近況報告
あけましておめでとうございますm(_ _)m
今年初のブログです。
去年12月に新しい会社に入り、現在はAI関係ではない仕事をやっています。
4月から念願だった機械学習関係のプロジェクトに入ることになりました。
DeepLearningは勉強していたのですが機械学習やscikit-learnは全然勉強していなかったので
昔買った本を読んで勉強中です。。
現在は、これの第1版を読んでいます。
このなかで、「ランダムフォレスト」という手法が面白かったので、
チュートリアルがてらFXの分析を実装してみました。
今日は、それを記事にしてみました。
ランダムフォレストでFX分析してみた
目標
- numpyのお作法をちゃんと守る(for文を使わず行列計算)
- ランダムフォレストの理論を理解する
ランダムフォレストとは?
弱い決定木をたくさん学習させて多数決する、的なやつです
説明は省略します。。
何をするの?
<翌日の騰落を当てる>にあたり、FXでよくきく「移動平均線」「ボリンジャーバンド」といったテクニカル指標はどの程度重要な指標となるのか?を分析してみました。
具体的には、移動平均線(25日,75日,200日)とボリバン(25日,75日,200日それぞれの±2σ、3σ)と前日終値の合計16変数を調べました。
データは過去10年分のUSDJPYの日足です。
ソースコード
総作成時間:4時間
参考書籍:上で紹介した書籍
import pandas as pd import numpy as np from sklearn.preprocessing import OneHotEncoder from copy import copy from sklearn.ensemble import RandomForestClassifier import matplotlib as plt IDX_HAZIMENE = 1 feature_name = [] def diviveData(term, in_data): out_data = np.array([[]]) for i in range(len(in_data) - term): if i == 0: out_data = [in_data[i:i+term]] else: out_data = np.append(out_data, [in_data[i:i+term]],axis=0) return out_data def movingaverage(in_data, isAppend=False): ''' 移動平均線のデータを作成 :param in_data: 作成に使うデータ :param isAppend: append対象ならtrue :return: MAのデータ np.array([len(in_data)]) ''' out_data = np.sum(in_data, axis=1) / len(in_data[0]) if isAppend: feature_name.append("movingaverage{}".format(len(in_data[0]))) return out_data def bollingerband(in_data, sigma): ''' ボリバンのデータを作成 :param in_data: 作成に使うデータ :param sigma: ボリバンのシグマ :return: ボリバンのデータ np.array([len(in_data)] ''' variance = np.sqrt(np.sum((in_data - movingaverage(in_data).reshape(-1,1)).astype(np.float64) ** 2, axis=1) / len(in_data[0])) # in_dataの最終行が最新の終値になっているので,in_data[:,-1] out_data = in_data[:, -1] + variance * sigma feature_name.append("bolingerband_date{}/{}sigma".format(len(in_data[0]),sigma)) return out_data def make_y_data(in_data): tomorrow_data = copy(in_data[1:]) out_data = in_data[:-1] - tomorrow_data out_data = np.where(out_data<0, 0, 1) # one-hotにencodeするための準備 out_data = out_data.reshape(-1,1) encoder = OneHotEncoder(n_values=2) out_data = encoder.fit_transform(out_data).toarray() return out_data data = (pd.read_csv("data/USDJPY.csv")).values data = data[:, 1] div25 = diviveData(25, data) div75 = diviveData(75, data) div200 = diviveData(200, data) pre_term = 0 #================= # ラベル作成 #================= y_data = make_y_data(data) #================= # データ作成 #================= # 2次元にしないとnp.appendがとおらないので整形 x_data = data.reshape(1, -1) for divdata, term in zip([div25, div75, div200], [25, 75, 200]): # データは少ない方にあわせる term_dif = term - pre_term x_data = x_data[:,term_dif:] pre_term = term # MA,BollingerBandをデータに加える x_data = np.append(x_data, np.array([bollingerband(divdata, sigma=2)]), axis=0) x_data = np.append(x_data, np.array([bollingerband(divdata, sigma=3)]), axis=0) x_data = np.append(x_data, np.array([bollingerband(divdata, sigma=-2)]), axis=0) x_data = np.append(x_data, np.array([bollingerband(divdata, sigma=-3)]), axis=0) x_data = np.append(x_data, np.array([movingaverage(divdata, isAppend=True)]), axis=0) # 前日の価格 x_data = np.append(x_data, [data[200-1:-1]], axis=0) feature_name.append("yesterday") # 当日の価格を1とした相対的な値に変換 x_data = x_data / x_data[0,:] # 当日の価格を教師データからのぞく x_data = x_data[1:,] #================= # 機械学習にかける #================= # 前処理 x_data = x_data.transpose() # x_dataは最新日のデータは除く(正解がわからないため) x_data = x_data[:-1] # y_dataをx_dataにあわせる y_data = y_data[-len(x_data):] clf = RandomForestClassifier(criterion='entropy', # 不純度 n_estimators=1000, # 決定木の数 random_state=1, # 乱数を固定 n_jobs=-1, # 使うコア数(-1:ぜんぶ) max_depth=10, # 決定木の深さ max_features='auto') # 決定木で使う特徴量("auto":sqrt(特徴量数)) clf.fit(x_data, y_data) importances = clf.feature_importances_ indices = np.argsort(importances)[::-1] for i in range(x_data.shape[1]): print("{} : {:.6f}".format(feature_name[indices[i]], importances[indices[i]])) print(clf.feature_importances_)
結果
movingaverage25 : 0.073916 bolingerband_date25/2sigma : 0.073495 yesterday : 0.070974 movingaverage200 : 0.069467 movingaverage75 : 0.069117 bolingerband_date25/3sigma : 0.065644 bolingerband_date25/-2sigma : 0.064432 bolingerband_date25/-3sigma : 0.062237 bolingerband_date75/3sigma : 0.059920 bolingerband_date75/2sigma : 0.059884 bolingerband_date200/3sigma : 0.056606 bolingerband_date75/-2sigma : 0.056600 bolingerband_date75/-3sigma : 0.056141 bolingerband_date200/-3sigma : 0.054896 bolingerband_date200/-2sigma : 0.053710 bolingerband_date200/2sigma : 0.052961
25日移動平均線、25日の2sigmaボリバンが相対的に大事な指標みたいです。
感想
ディープラーニングとの違いって?
「(ディープラーニング以外の)機械学習は特徴量を絞らないと次元の呪いが〜〜〜」ってずっと思っていたのですが、ランダムフォレストは特徴量を増やしても大丈夫なんでしょうか。
そうなると、ディープラーニングと比べてメリットデメリットは何なんでしょう。
感覚的には
ディープラーニング > ランダムフォレスト
ランダムフォレスト > ディープラーニング
- 「なぜこの結論に至ったか」の説明がしやすいです。ランダムフォレストは上のように特徴量の重要度が出せるので・・・
- 学習に必要なデータが少なくてすむ?(一般論)
こんな感じでしょうか。。
特徴量の重要度は、1変数でしかできない?
説明変数の組み合わせで重要度を出したいです。たとえば、25日移動平均線と25日+2sigmaボリバンを組み合わせるとどれだけ重要な特徴量になるのか?など調べられると嬉しいです。
パラメータ
パラメータチューニング全くしてないので、してみるとどうなるのか。とくに、木の深さってどれくらいが推奨されるのだろう。。とか思ったり。。
numpy
for文使わず綺麗にかけた!ような気がします。笑
ただ、ゴリ押ししている部分も多いので汚いですね
3ヶ月後に読んだらなんのこっちゃってなりそうです・・・
その他
- 久々なので気合入れて書こうと思ったのですが最後の方投げやりです。。すいません。
- 今週土曜日3/17に某所でDeepLearningのハンズオンをやります。
定員30名に対して倍くらい人が来ているということもあり緊張しますが、がんばります!