💸

Signalsのモデリングについて

2021/12/20に公開

これは Numerai Advent Clalendar 19日目の記事です。

今年のカレンダーでは、私が貯めてきたSignalsのノウハウを公開していきたいと思います。昨日行われたNumerai Japan Meetup で私が発表する内容を肉付けした内容になっているので、こちらをご覧いただくとわかりやすいかと思います。
ちなみに本記事では、主にGBDTモデルを使うことを想定して書いています。

もくじ

  • 相関の高すぎる特徴量は省く
  • ハイパラsubsample とcolsample_bytree は事前に決めておく
  • 過学習を避けるには、特徴量重要度とn_estimators

相関の高すぎる特徴量は省く

線形モデルでは、相関の高い特徴量があるとモデルが安定しない多重共線性という現象があります。似たような現象がツリーモデルにもあるらしく、代替効果と呼ばれているそうです。
代替効果はモデルの解釈性(特徴量重要度のこと)に影響を及ぼすだけでなく、モデルのパフォーマンスにも影響を与えます。そのため、代替効果を避けることは非常に重要な課題です。
代替効果を避けるにはどうしたら良いのか?単純に相関の高い特徴量を減らしていきましょう。以下の図が、私の特徴量を削る前と削った後です。特に、相関が1.0の特徴量は意味がないので、必ず処理しましょう。

ちなみに削る特徴量の基準は、私は0.96~0.98くらいだと見ています。これでも十分に高いですが、今のところ、これらの特徴量だと過学習などに対処できているように感じます(この点については後述)。また、Meetupでの質問でも出ましたが、よく見ると相関が0.98を超えている特徴量を削減していませんね。この辺りはある程度個人の裁量によると思います。最後に、当たり前かもしれませんが、相関1.0のものは必ず省きましょう。

ハイパラsubsample とcolsample_bytree は事前に決めておく

ハイパーパラメータの中には、事前にある程度決めることができるものがあります。例えば、XGBoostの場合ですと、subsamplecolsample_bytreeです。
テクニカル指標などの特徴量を生成するとき、どうしても時間方向に統計処理をする必要があります。ある程度安定した値を設定したい場合には長めの期間の統計処理を行う必要があるので、ターゲットとの重複が生じざるを得ません。しかしそうすると、各データ間に重複があることとなり、機械学習の基本的な仮定である、i.i.d. が成り立たなくなってしまいます。その結果、ツリーモデルを学習させると似たような木が多数生成されることとなり、過学習の原因となり得ます。そこで、subsampleの値を上手く設定することで、できるだけi.i.d.の仮定が成り立つようにし、木ごとの違いを出すために、colsample_bytreeを上手く設定します。

subsample の設定について

これには、ファイナンス機械学習に載っている平均独自性を利用すると良いです。平均独自性の算出方法はMarcos氏のスライドに書いてあったので、引用します。

初見ではよくわかりませんよね?しかしSignals ではみなさん日足データを使っているはずですので、その場合には以下の式で簡単に算出することができます。

       日足データでの平均独自性 = 1 / (target と特徴量の重複回数)

例えば、特徴量生成に、最大で60日間の移動平均を使用していた場合には、特徴量のSignalsのターゲットの重複は60/5 = 12 回ありますから、平均独自性 = 1/12 となります。従って、subsample = 1/12 と設定してあげると、良い感じのパフォーマンスが出ることが期待されます。
subsample の値には、こうして得られた値を設定してみてください。

colsample_bytree の設定について

これについては、若干個人的な見解が含まれています。もととなるアイデアは、ファイナンス機械学習において、代替効果を避けるためにRFのハイパーパラメータmax_features=int(1) と設定するところから来ています。要するに、いかにして様々なバリエーションの木を作るかをこのハイパーパラメータを設定することで試みようとしています。
まず、木が生成される特徴量の中に、重複が含まれて欲しくないです。仮に、全ての特徴量を使った場合には、強い特徴量に引っ張られて、似たような木が生成されることが想定されます。そうなると、それらの特徴量が効いている間は良いですが、うまく効かない場合には大きなドローダウンを喰らう可能性があります。Numerai の場合ですと、ある一定期間のパフォーマンスはすこぶる良くても、別の期間では大きくマイナスになるようなシチュエーションを指すと思います。このようなことは起きてほしくないはずです。
そこで、それぞれの木で使われる特徴量を調整して(つまりcolsample_bytreeを上手く設定して)、それぞれの特徴量が使われるチャンスを均等に分け与えることを考えます。
例えば、depth = 5 だった場合には、特徴量が木の生成に使われる回数は、最大で2^depth - 1回です。そこで、使用される特徴量の数を、2^depth - 1個にするために、colsample_bytree を以下の値で定めます。

       colsample_bytree = (2^depth - 1) / (feature数)

この値の信憑性を確認するためには、かなり強かった旧データセットのexample model はハイパーパラメータcolsample_bytree=0.1で設定されていたことを思い出すと良いかと思います。example model のdepth はdepth = 5 で、feature数は310だったので、上述の式に当てはめてみると (2^5 - 1) / 310 = 31 / 310 = 0.1 となります。
このハイパーパラメータの設定が本当に良いのかはわかりませんが、私はこうしてハイパーパラメータを設定しております。ただ、少なくとも、colsample_bytree は、木のバリエーションを増やすためにはある程度低い値を設定しておくことは必要かなと思います。

過学習を避けるには、特徴量重要度とn_estimators

Numerai において、予測モデルが上手くパフォームしているのか否かを判定するのは相当難しいです。実際、バリデーションでは良くてもライブではパフォーマンスが悪い、所謂過学習しているようなモデルは割とあると思います。バリデーションの結果は、作成したモデルを却下するのには使えますが、モデルが今後もパフォームすることを保証するものではないからです。ここでは、バリデーションの結果以外で、モデルの過学習の判定材料となるものを紹介します。

特徴量重要度のバランス

ツリーモデルの特徴量重要度に偏りがある場合には、モデルがその偏っている特徴量に大きく依存していることが考えられます。そのため、その偏りのある特徴量にモデルが左右されてしまい、好ましくないです。そこで、特徴量重要度の偏りがないか、ある場合にはそのリスクを取ることができるのか、をチェックしておくことを勧めます。
ちなみに以下は私のモデルの特徴量です。

上位に来ている特徴量は、カテゴリカル変数であるcountry, sector, industryです。これらの特徴量は高いのですが、有意に効いてきそうな特徴量でもあるので、このリスクは受け入れています。しかしながら、これら以外の特徴量の重要度は軒並み似たような大きさになっているので、バランスが取れているものだと解釈しています。
このとき、先に述べました代替効果を避けておかないと、重要度がモデルの実体を表していない可能性があります。また、特徴量の粒度も重要度に影響を与えることにも注意しておきましょう。今回提案しているbinning 処理を施した特徴量では、粒度が揃っているので問題になりませんが、country, sector, industry などのカテゴリカル変数は粒度が高いため、特徴量が大きめに出てしまいます。このリンク先の記事が参考になるかと思います。

n_estimators を増やす

GBDTモデルを使っている方は、n_estimators=2000~3000くらいに設定しているのではないでしょうか。Signalsでは、n_estimatorsを(主に小さく)いじることで、バリデーションでのパフォーマンスが高いモデルを作ることができます。しかしその発見は真の発見でしょうか?それを明らかにするためには、n_estimators=5000~20000などと大きな値でアンサンブルを取ると良いです。良いモデルであれば、n_estimators=2000~20000くらいの変化でも、モデルの性能はほぼ変わらないか、向上したりします。もし、n_estimatorsの値を増やしてモデルのパフォーマンスが大きく劣化したのであれば、そのモデルは過学習していることを疑った方が良いです

過学習の主な要因としては、n_estimators=100など、値が小さすぎることと、特徴量が十分でないことが挙げられます。n_estimators は十分に大きな値(2000~5000)に設定し、十分に増やした特徴量で学習を行いましょう。特徴量数については、100以上あることがおすすめです。良い感じになるように作ってください。
モデルをデプロイする前に、n_estimatorsをいじってモデルの過学習を調べてみてはいかがでしょうか。

これまでのまとめ

  • corr sharpe = CLEAN DATA × 銘柄数 × モデリング
  • データの綺麗さはモデルに直結。異常値を上手く取り除きましょう
  • 銘柄数は大きければ大きいほどcorr やcorr sharpe が上がる。yfinance などで取得しましょう。
  • モデリングは容易に過学習につながるので丁寧に行うことができる。いくつかのパラメータは、ある一定のフィロソフィーに従って決めておくのが無難。
  • バリデーションの結果を信じるより、自分が作ったモデルそのものを信じるというパラダイムシフトが起こるのではないかと思います。

Numerai Meetup での質問事項

時間がないので後日答えます。しばしお待ちを。

最後に

今年もNumerai Advent Calendarを作成させていただきました。これまでの経験によって得た内容を大量にポロリした感じです。今回の一連の記事をもとにSignalsに参加する方々が増えることを願ってやみません。同じやり方で参加してくる人が増えてくるのだとすれば、私のMMCが下がるはずですので、しばらくはMMCの変化を観察させていただきたいと思います!DMには基本返答しますので、質問事項などがある人は、DMを送るか、あるいは本記事のコメントに質問事項を投げてくれますと、答えられる範囲でお答えします。なんでも聞いてみてください。

それではみなさん、Numerai or Die!

Discussion