Kaggle : PSPコンペ復習

PSPコンペが終了したので、上位解法で気になった部分を復習していこうと思う。
個人としてはソロ銀を獲得できたので割と満足している。
![スクリーンショット 2023-07-22 12.21.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2746031/7d42e106-d018-14ad-7421-f152a1699054.png)

上位陣の多くはGBDT＋NNのEnsembleであった。モデルに関しては、自分が使用したGBDTに焦点を当てて復習していく。

https://www.kaggle.com/competitions/predict-student-performance-from-game-play/overview

# 1st placeの解法

GBDT + NN Ensemble

https://www.kaggle.com/competitions/predict-student-performance-from-game-play/discussion/420217

## Trust your CV
毎回言われていることだが、彼らは特に重視していた。Trainデータは外部データも含めて約37000レコードであったのに対し、LBデータは約1500レコードであったため信頼に値しないと確信したようだ。**"We only added features that improved the CV for sure".** というように、CV Scoreが0.0003以上向上した場合のみ特徴量を採用した。自分は「今回のLBはあまり信用しない方がいいだろうな」とCVとLBの関係をみて感覚的に捉えていたが、ここまで定量的に捉えられてはいなかった。この[Discussion](https://www.kaggle.com/competitions/predict-student-performance-from-game-play/discussion/399802)を見ても、ここまで考え切れている人はあまり多くはなかったのではないだろうか。

## GBDTは数千程度の特徴量なら扱える
本コンペでは様々な集計の経過時間とカウント数が主に特徴量として使用されていた。そのため、特徴量が非常に多くなり、実際に彼らの特徴量は各level_groupそれぞれに対して663,1993,3734であった。彼らはこれらの特徴量をXGBoostに学習させて、非常に高いCV、LB scoreを出した。GBDTは無駄な特徴量を増やしても精度が落ちにくいと聞いてはいたが、ここまで多くの特徴量に対しても過学習することなく精度を向上させることができるとは思わなかった。もちろんCV scoreなどを見ながら調整する必要はあるが、数千程度の特徴量であれば過学習することなく処理できるということは頭に入れておこう。

# 3rd placeの解法

GBDT + NN Ensemble

https://www.kaggle.com/competitions/predict-student-performance-from-game-play/discussion/420235

https://www.kaggle.com/competitions/predict-student-performance-from-game-play/discussion/420274

## 特徴量選択の難しさ

本コンペでは上記のように非常に特徴量を多く作成するのが正攻法だったため、多くのチームが特徴量選択に取り組んでいた。実際に自分も試みたが、CVだけが向上し、LBが悪化してしまったので特徴量選択は取り入れなかった。これには明確な理由があった。YYYKRKさんが以下のように述べている。

"When feature selection, I did it by out of fold (per fold×question). Otherwise, it would cause leakage, unfairly boost the CV score, and affect negatively ensemble weights, etc."

まさしく自分がここに記されているやってはいけない方法で特徴量選択をしてしまっていた。自分はCVで全てのfoldのimportanceの平均をとって、その上位を採用するという形式で特徴量選択をしていた。だがこれでは、**あるfoldでvalid dataとなるものが異なるfoldではtrain dataとして使われてしまうので、全体のfeature importanceの情報を合算するとリークしてしまう**のだ。これによりCVのみが不当に向上してしまう。従って、**バリデーションの際にはfold毎に特徴量選択を行う必要がある**。

だが、fold毎に特徴量選択をおこなったからといって、スコアが向上するという訳でもないようだ。実際に特徴量選択後の彼らのCVスコアはほとんど変化せず、LBスコアは悪化した。結果的に特徴量選択は行わない方針に変更した。おまけにfold毎に特徴量選択を行うことで以下のような欠点があると言及している。

- 特徴量の管理が難しくなる。
- 計算コストが増加する。
- 大体の場合、スコアはそこまで変化しない。

これまでの話を聞いていると、GBDTの場合には特徴量選択はしない方がいいのかなという気持ちになってくる。ただ、より多くの特徴量を作成して絞り込むことで精度を向上させることに成功した人もいるようなので、モデル次第なのかな。結局は試してみるしかない。

# 7th placeの解法

LightGBM

https://www.kaggle.com/competitions/predict-student-performance-from-game-play/discussion/420119

## Random seed average
そういえばなぜやらなかったのだろうか。MSCIコンペの時に有用性は実証したはずなのに完全に頭から抜けていた。次のコンペでは忘れずに実装するようにしよう。Jackさんは基本的にできるところではRandom seed averageを実行するというような印象を受けた。

- 各foldの特徴量重要度を求める際に、Random seed averageを実行 (fold0での特徴量重要度は3つのseedの平均をとるというように)
- 各foldでCVスコアを算出する場合にもRandom seed averageを実行

## 学習データ全体で再学習をして推論する

Jackさんも3位の方々と同様にfold毎に特徴量選択をおこない、4つのfoldのスコアを平均してCV scoreを算出した。その後、CVで作成した4つのモデルを使わずに学習データ全体を再学習していた。自分も過去に何度か再学習して推論をしたことがあるが、毎回スコアがCVのモデル以下かつ時間が余計にかかるので最近は全くやっていない。そもそもCVの際に設定したハイパーパラメータや特徴量をそのまま使用すれば再学習した場合にも高い精度を出すことができるのか？Jackさんはハイパーパラメータ及び選択する特徴量数はCVでの値を使用していた（round数はCVで求めた最適な値を使用）。Jackさんがどれほどの調整を重ねたのかは分からないが、Jackさんが採用している時点でCVで設定したハイパーパラメータや特徴量をそのまま使用する方針でベースはいいのだろう。

ちなみに、再学習をする際には特徴量重要度はfold,seedまとめて平均をとって特徴量の順位付けをする。つまり、各特徴量に対して12個（4fold*3seeds）の平均値をとる。CVの際にはleakを避けるためにfold毎に特徴量重要度を求めていたが、再学習の際にはleakという概念がないのでまとめて考えていい。

# 9th placeの手法

LightGBM + Catboost

https://www.kaggle.com/competitions/predict-student-performance-from-game-play/discussion/420046

## 特徴量選択について念押し

Makotuさんも3位の方々、Jackさんと同様にしてfold毎に特徴量選択をおこなった。上位勢の間では当たり前なんだろうね。まあ少し考えれば分かることだしなぁ。己の弱さが身に染みる...

"For feature selection, I simply used the top 500 features based on their importance. To prevent leakage, I selected the feature importance for each fold, and retrained the model for each fold. For example, when training fold1, I first train with all features, then select the features using the fold1 model, and retrain the fold1 model with the top 500 features."

## 単純平均Ensembleでスコアを確認する方法

自分は今回Ensembleをしてもスコアが改善されなかったのでおこなってはいないが、Matokuさん含め多くの上位陣がEnsembleでスコアを伸ばしていた。過去のコンペではEnsembleをすることで自分もスコアを伸ばしてきたのだが、恥ずかしながらEnsembleが効いたかどうかをLBのみから判断していた。今回ようやくEnsembleのCVスコアを知る方法を勉強したのでまとめていく。

https://www.kaggle.com/competitions/siim-isic-melanoma-classification/discussion/175614

ここでChrisが説明してくれている。Chrisが言っているので信頼できない訳がない。
1. model1, model2におけるCV予測値としてoof1_preds, oof2_predsを取得する（適切な評価指標を用いてoof_targetとの関係を計算をすることで、singleモデルのCVスコアを算出することができる）。
2. model1, model2を使用して、テストデータに対する予測値としてsub1_preds, sub2_predsを取得する（これらがsingleモデルの場合の提出ファイルとなる）。
3. EnsembleのCVスコアを得るためには、oof1_predsとoof2_predsを適当な比率で平均をとることでEnsemble_predsを作成し、singleモデルの場合と同様に適切な評価指標を用いてoof_targetとの関係を計算をする。これによってEnsembleのCVスコアを得ることができる（Chrisが書いているように、様々な比率を探索する）。
4. 最適な比率を決定したら、その比率でsub1_predsとsub2_predsの平均をとり、Ensemble_sub_predsを作成して提出する。

# 総括

個人的には初めてソロ銀を取れて結果面で言えば満足している。だが、上記のようにまだまだ知らないことだらけで上位人とは圧倒的な差を感じさせられた。まあここに書いてあることを少しずつ理解しながら実装していくしか上に行く方法はないのだろう。今回学んだ内容はどれもすべてのコンペで使うことができそうなものなので、今後のコンペでは積極的に試していきたい。