[Numerai] 成功が約束された特徴量を試してみる

4 min読了の目安(約3600字TECH技術記事

この記事はNumerai Advent Calendarの12/21分の内容です。

はじめに

Numerai Tournamentでは、匿名特徴量が310個与えられます。金融ガチ勢の方々だとそれぞれどういったものか、なんとなく察しがついているのかもしれませんが、自分は金融何もわからないマンなので何もわかりません。ただモデルにそれらを投げて、targetとの関連を見つけてもらうマンです。

そんな中でも、与えられた匿名特徴量をどうにか用いて特徴量エンジニアリングをすることができれば、他の参加者と差をつけられるであろうことは想像に難くありません。Numerai Tournamentで提供される特徴量はTargetと相関しているものが多く、与えられた特徴量だけでそれなりのスコアを出すことができてしまうため、多くの参加者がそれをいいことに特徴量エンジニアリングをしていないと思われるからです。

実際、匿名特徴量で特徴量エンジニアリングをするのは、ドメイン知識が使えないため難しいです。ただ幸いなことに、Numerai Tournamentのような、匿名特徴量でtrainとtestが与えられているテーブルデータ形式のコンペにおいて、ほぼ間違いなく効くであろう特徴量エンジニアリング手法があります。そう、

次元削減

です。

本当に次元削減特徴量って効くんですかー?

KaggleではMoA - Mechanism of Actionという、遺伝子発現等の情報から薬物動態を予測するコンペが開催されました。私も参加しました。結果は聞かないでください。

いま大事なのは、データの形式が比較的Numerai Tournamentと似ていたことです。匿名特徴量が数百与えられ、train, testのデータも与えられていました(厳密にはtestは一部のみ与えられていました)。

このとき活躍したのが、PCA特徴量でした。上位解法でもほぼほぼ使われていたように思います。PCA (Principal Component Analysis)についてはここでは説明を省きますが、「何それおいし(略」という方は、以下の記事等ご参照ください。

Coursera Machine Learning (8): 教師なし学習 (K-Means)、主成分分析 (PCA)

最も一般的な次元削減手法のPCAですが、MoAにおいては、train, test両方を使って次元削減特徴量を作ることでスコアを伸ばしていました。

厳しい現実の世界においては、testデータは往々にして未知の世界(未来とか)からやってくるもので、testデータを使って特徴量を作る、なんてことは許されません。

しかし、MoAやNumerai Tournamentなど一部のコンペにおいては、それが可能です。Testデータを含めて特徴量を作ることになるので、testでも汎化する特徴量ができると期待されます。Numerai Tournamentの文脈で言い換えると、

「Live eraの情報を含めた特徴量ができるので、その特徴量はLive eraにも汎化して予測精度もぐふふふふ」

実装

単純に、

from sklearn import decomposition

# all the features in the Numerai Tournament
features = train.columns[train.columns.str.startswith('feature')].values.tolist()

# concatenate train and test
all_data = pd.concat([train[features + ['era', 'target']], 
                      tournament[features + ['era', 'target']]], 
                      ignore_index=True)
		      
# PCA using all the data
pca = decomposition.IncrementalPCA(n_components=100)
emb = pca.fit_transform(all_data[features].values)

# assign
for i in range(emb.shape[1]):
    all_data[f'pca_{i+1}'] = emb[:, i]

と、trainとtestを合体したものにPCAをかけるだけです(メモリの都合で、通常のPCAではなくIncrementalPCAにしています)。

PCA特徴量を第何成分まで入れるか?ということに関しては、100成分まで入れています。なぜ100にしたのかというと、ここまで入れると、PCA特徴量のexplained varianceが9割を超える、すなわちもとの310個の特徴量が持つ情報の9割は100個のPCA特徴量が保持している、ということになるので、悪くないんじゃね?という判断です。

このPCA特徴量を加えることにより、+100個の新特徴量ができました!

これが元の310個のみの特徴量の場合と比べて、どれくらい精度改善があるか見てみます。

検証

モデルはみんな大好きlightGBMを使います。

import lightgbm as lgb
model = lgb.LGBMRegressor(max_depth=3, feature_fraction=0.4, seed=42)

これで、オリジナル310特徴量のみのtrainデータをfitします。これがbaseline modelですね。
次に、+100PCA特徴量を入れたtrainデータで別にfitします。これが今回検証するmodelです。

fitが終わったら、validationデータに対するスコアを計算します。自分は、validation期間を
(1)全期間
(2)前半(予測が簡単な時期、あんま参考にならん)
(3)後半(予測が難しい時期、liveに比較的近く参考になる)

に分け、それぞれで以下を計算しています。

  • correlation
  • correlation sharpe
  • correlation mean(by era)
  • correlation std(by era)
  • max drawdown
  • feature exposure
  • max feature exposure

さあ結果です!

結果

  • baseline

  • +PCA

おかしいなSharpeが悪化しているぞ
おかしいなmax drawdownも悪化しているぞ

直接的な精度を表すCorrelationやcorrelation mean (by era) は+PCAモデルの方が良いですね!

しかも、Burning eraを乗り切るのに重要といわれる、feature exposureも+PCAモデルの方が良いですね!(feature exposureは、今回オリジナル特徴量でしか計算してないので良くなって当然)

MoAで活躍したtrain+testから作られる次元削減特徴量、皆さんも(自己責任で)Numerai Tournament本番運用なさったらいかがでしょうか👼