Kaggle : MSCIコンペ振り返り

先日、MSCIコンペの順位が確定し、銀メダルを獲得することができたので振り返りでも綴っていこうと思う。どんな風に考えて何を試したのかということを時系列順に辿っていく。また、上位陣の解法からの学びなども記す。
![名称未設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2746031/143be802-5376-3c3f-8603-cf1ca8f931d7.png)

https://www.kaggle.com/competitions/open-problems-multimodal/overview

# 参加したきっかけ
　一つは、自分の研究内容と比較的近かったから。KaggleはTitanicのチュートリアルを眺めたことがある程度で本気でやったことはなかったのだが、Twitterでたまたまバイオ系のコンペがあることを知って参加してみた。後述するが、ドメイン知識を活用できた部分はほとんどなかった（笑）。
　また、来年からIT企業で働くことを考えると、コードにもっと慣れておくべきだと考えたことも理由の一つだ。自分の研究ではコードを書くことはあまりしないので、pythonくらいは書けるようになっておきたかった。実際、参加する前と比較したらだいぶ上達したように思う。

# 軌跡
## 4週間前
　ひとまずは、公開されているコードの中で最もスコアが高く、多くの人が使用しているであろうKernelを真似してMLPモデルを作成してサブミットした。これでは当然上位に食い込むことは厳しく、メダル圏には届かなかった。

https://www.kaggle.com/code/ambrosm/msci-citeseq-keras-quickstart

　そこで、ドメイン知識を活かした特徴量の生成に取り組んだ。目的変数である各タンパク質をコードする遺伝子はある程度決まっており、それらは直接的にタンパク質発現に影響すると考えられる。そこで、それらの「重要な遺伝子」を自分で調べて特徴量に追加した。140のタンパク質一つ一つに対して調べる必要があったので非常に面倒だったが、これが非常に有効に働き一気に銅圏に乗ることができた。これが唯一のドメイン知識の活用場面である。
　また、Permutation importanceを使って特徴量の重要度を調べてみた。その中で重要度の下位5つを特徴量から除外したがスコアの向上は見られなかった。調べてみると、Permutation importanceでは多重共線性が問題になり、相関がある特徴量があると重要度が過小評価されることが分かった。実際に、過小評価されていると考えられる特徴量は残してそれ以外を除外すると、若干ではあったがスコアが向上した。このように、Permutation importanceを使う際には多重共線性に気を遣う必要があるので注意が必要。

https://qiita.com/kenmatsu4/items/c49059f78c2b6fed0929

## 3週間前
　当時の銅圏のスコアがでる以下のコードが公開された。この中で自分にとって一番画期的だったのが、tSVDで次元圧縮をした後に重要度の低い列を除去するというものである。従来までは次元圧縮を施して終わりだったので、この週は最適な圧縮率および除去する列数の探索に費やした。順調にスコアを伸ばすことができ、銀圏に乗ることができた。

https://www.kaggle.com/code/pourchot/all-in-one-citeseq-multiome-with-keras

　また、目的変数であるタンパク質の発現量と各遺伝子の発現量の相関を考えている以下のKernelが公開された。実際に自分も試してみて、ある閾値よりも大きい相関を持つ遺伝子を新たな「重要な遺伝子」として特徴量として追加した。だが、スコアはCV,LBの両者において伸びなかったので採用しなかった。上位陣は割とこの手法によって得た特徴量を使用していた。違いはどこにあったのだろうか。

 https://www.kaggle.com/code/fabiencrom/msci-correlations-eda-citeseq

　さらに、アンサンブルのためにLGBMのモデルも作成した。特徴量はほとんどMLPと同じものを使用したのだが、最適な圧縮率および除去する列数がMLPとは異なったため、こちらでも最適解を探索する必要があった。非常に面倒であったが、他に良いアイデアも思いつかなかったので地道に進めて行った。Catboostも試したが、LGBMの方がスコアが高かったためGBDTのモデルとしてはLGBMを採用した。

## 2週間前
　アイデアが全く思いつかなくなった。一応毎日考えてはいたが、モチベーションも下がり始めてきた。とりあえずPCは動かしておきたかったのでパラメータチューニングを始めた。最初はKeras Tunerを使用していたのだが、あまりうまくいかなかったので手動で調整した。原理が分かりやすい学習率やバッチサイズを中心にチューニングを行い、少しずつスコアを上げることができた。LGBMに関しては原理を詳しく分かっていたし要素もMLPほど多くはないので、細かい部分まで調整することができたと思う。
　ここから単純な加重平均によるアンサンブルを試し始めた。LGBMのスコアはMLPと比べると大きく劣るがアンサンブルするとLBの順位が7,8位上がり効果を実感することができた。

## 1週間前
　ここでno-magicさんとチームを組んだ。本コンペではPublic LBとPrivate LBのデータ分布が大きく異なるため、どのようなCVモデルを最終サブミットに使用すべきかを相談する相手が欲しかったから。実際にno-magicさんと議論して、Private LBをある程度（完全にではないが）模倣して実験することによって使用するCVモデルを決定した。Kaggleの経験が少ない自分にはこの辺りの技術・アイデアがなかったので非常に助けられた。
　その後は逐一コミュニケーションを取りながら細かい調整をおこなった。最後の1週間ということもありLBの争いが激化し、最終的にはPublic LBは銅圏まで落ちた。だが、自分達のCVを信じて最もCVスコアが高いファイルを最終サブミットとして選択した結果、Private LBでは銀圏までshake upすることができた。

# 感想
　本気で取り組んだ初めてのコンペであったが、32位という順位を取ることができて非常に嬉しかった。データを分析してどのような特徴量を作成すれば良いかを考えるのは非常に楽しく、ピークの時には四六時中考えていたように思う。おかげで本業の研究があまり進まず、教授にちょっぴり怒られたことも今となってはいい思い出だ。
　時間と能力不足の関係でstackingは試せなかったが、上位陣の中にも使用している人が結構いるのでしっかり勉強して実装できるようになっておきたい。
　自分のようなKaggleの初心者は、プライドなどは捨ててまずはパクることから始めてもいいと思う。そこから少しの改善を加えるだけで、今回のように全然メダル圏内に入ることができる。あるメガベンチャーのインターンでこのように言っていた。「新規事業を考えるときは**TTP-S（徹底的にパクって"進化させる"）を常に意識しろ**」。まさにKaggleでも同じことが言えると思う。技術は過程で学んでいけばいい。
　今後はW杯や修論の執筆とかで時間が取れないので、一旦2月までKaggleは中断かな。2,3月にもコンペに参加して今年度中にKaggle expertになれるように努力を続けていこう。

# 上位陣の解法について気になった点
## 決定木を特徴量選択のために使用する（4th, 6th, 11th）
Since the feature importances of random forest may apply to NN and other models as well. So I selected 128 top feature importances of the random forest model.(4th)

Search using xgb feature importance: for cite, we fit multiple xgb for each target (full 22k feature) then choose the top 5 important features of each target. In total, we get around 500 important features for our model.(6th)

For Citeseq, I trained 140 shallow LGBM models (one for each target) using the full set of data. The goal here was not to use the models themselves, but to see which features were important for each target. I used the top 100-200 features per target in the later, deeper modeling.(11th)

決定木では特徴量の重要度を容易に定量化・可視化できる。これを活用し、決定木で重要度が高かった特徴量を他のモデルでも使うことができるようだ。多くの上位陣が採用しており、一般的な方法であるようだ。

## 多様なモデルをアンサンブルする（5th, 6th）
I tried different activation functions and ensemble them, and this greatly improved CV.(5th)

Dimension reduction: we use different methods to increase the diversity for the final ensemble: 240 n_components SVD/quantiledPCA and denoise Autoencoder (256 latent dims).(6th)

活性化関数を変更したものや次元圧縮手法を変更したものをアンサンブルしている。自分は異なる機械学習モデルくらいしかアンサンブルしなかったが、より細かい調整も有効に働くようだ。

また、この[Discussion](https://www.kaggle.com/competitions/open-problems-multimodal/discussion/363230)で議論されているように、異なる機械学習モデルをアンサンブルする場合にはアンサンブルしてスコアが上がりそうか否かという判断基準があるようだ。以下に記したが、単純に言えば「アルゴリズムが全く異なり、強いモデルはアンサンブルがうまく働く。一方、アルゴリズムが近く、弱いモデルは意味がない」というものだ。まぁ当然と言えば当然か。

In my experience, the blending works in following order;
①good and highly different models > ②not good but highly different models ≒ ③good and slightly different models >> ④not good and not different models.

参考

https://qiita.com/Ishio/items/6d7378551c2df81aeac1

アンサンブルが効くかの指標としてピアソンの相関係数やコルモゴロフ–スミルノフ検定を使用するようだ。