特徴量選択について
テーブルデータへ機械学習モデルを適用する場合、予測精度を向上させるのには一般的には特徴量エンジニアリングを行うことが重要になります。
kaggleなどの機械学習コンペでは、数千を超える特徴量を使用しているケースを良く見かけます。GBDT系のモデルでは、目的関数(誤差関数と正則化項の和)を最も減少させる変数を使用して分岐を進めるため、内部で暗に特徴量選択が行われています。
しかし、入力の特徴量が多すぎると計算時間が増えたり、ノイズを学習すると汎化性能が落ちることもあるので、入力する段階で特徴量選択が必要になる場合もあります。
決定木をベースとしたのアルゴリズムでは、各変数がどれくらい目的関数を減少させたかをし表す特徴量重要度(feature importance)が参照できるので、ここから重要度が低い対象を除外するのがナイーブなやり方かと思います。
今回紹介するBorutaという特徴量選択の手法は、特徴量重要度を元にノイズより有意に重要度が高いかを比較して特徴量を選択する方法で、通常の重要度算出より幾分有効だと考えられています。
昔参加したコンペでは、borutaを使用した手法で若干スコアが改善しました。

Borutaのアルゴリズムの理解
大きな流れとしては下記のような処理となります。

STEP1
オリジナル特徴量をコピーして特徴量(shadow features)を作りだす
STEP2
新しく作成した特徴量(shadow features)の値をシャッフルする
STEP3
全部の特徴量を合わせて決定木系のアルゴリズムで予測を行い、各特徴量の重要度を得る
STEP4
オリジナル特徴量の重要度とシャドウ特徴量の一番大きな重要度の値を比較して何度上回ったかをカウントする
STEP5
学習を繰り返して各変数毎にシャドウ特徴量より重要度が上回る回数が低いものは除外する
除外判定はカウントデータが二項分布に従う帰無仮説を棄却するかを判断しているようで、Confirmed(有意で重要), Tentative(有意とは言えない), Rejected(有意で重要ではない)に分類されるようです。
気持ちとしては、シャドウ特徴量はランダムな変数なので、当然特徴量重要度が低くでるはずですが、それよりも低いという事は不要な特徴量として考えられるということになると思います。
実装
ライブラリーがあるのでインストールすれば実装は簡単ですが、kaggleのdocker imageを使えばimportするだけなので楽ちんです。(dockerわからない場合はUdemyの米国AI開発者がゼロから教えるDocker講座がオススメです)
実装はコチラのnotebookを参考にしてrandom forestを用いています。Numeraiのデータを使って学習データを1割にランダムサンプリングして特徴量選択を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import pandas as pd from sklearn.ensemble import RandomForestRegressor from boruta import BorutaPy train_df = pd.read_pickle('../input/processed/train_df_int_mapped.pkl') # 学習データ読み込み train_df = train_df.sample(frac=0.1).reset_index(drop=True) features = [c for c in train_df.columns if c not in ["era", "id","data_type", "target"]] target = train_df["target"] rfc = RandomForestRegressor(n_estimators=200, n_jobs=-1, max_depth=6) # define Boruta feature selection method feat_selector = BorutaPy(rfc, n_estimators='auto', verbose=2) # find all relevant features feat_selector.fit(train_df[features].values, target.values) # number of selected features print ('\n Number of selected features:') print (feat_selector.n_features_) # show selected features feature_df = pd.DataFrame() feature_df["feature"] = features feature_df["rank"] = feat_selector.ranking_ feature_df.sort_values("rank")[:feat_selector.n_features_] |
BorutaPyにn_estimatorsをautoで渡していますが、これは繰り返し計算の回数を表します。値を設定してもよいですが、autoを渡すとデータセットに応じて自動で選んでくれるようです。
上記のコードで私の環境(10 core 20 thread)で学習データが5万件でも10分ほどかかるので、データ量が大きいと計算資源がないと少しツライですね。
実行結果310個の特徴量の内有意にシャドウ特徴量より重要度が高い対象は2個という判定だったので、今回の結果ではそのまま使うのは難しいことがわかります。
そもそもNumeraiのデータは株価の時系列データで、ノイズが多いことを考えると有意に重要である特徴量が見つかりにくのは当然かもしれません。
まとめ
昔のコンペで使用したBorutaですが、計算コストが高いことと、決定木のパラメータの設定が難しい(今回はn_estimator=200としているが、ここはoverfitやunderfitの可能性がある)ので、何度か実験を行ってからじゃないと個人的には中々使いにくい印象です( ゚Д゚)
他にも特徴量選択方法はあるので、それらも勉強していきます。