はじめに
KaggleのAmexコンペにソロで参加して銀メダルを取れたので備忘録も兼ねて振り返っておく。
自分について
少しだけ自分について説明しておく。
Kaggleを始めて約半年、初参加のH&Mコンペではソロ銀メダルを取ることができたので当時もQiitaに記事を書いた。
https://qiita.com/tetsuro731/items/972847199ec2ecaeb058
今回メダルを取ったことで、無事Kaggle Competition Expertになることができた。やったね。
どんなコンペ?
https://www.kaggle.com/competitions/amex-default-prediction
Amexカードのユーザー履歴から将来的にdefault (破産)するかを予測する。
正解ラベル(target)として破産したユーザーは1, それ以外のユーザーには0が付与されている。
ユーザーごとに約一年分の行動履歴が与えられている。
上位者には賞金が与えられる他、希望者にはAmex採用プロセスに進む権利 が与えられる。
Kaggleで転職って素敵ね。(ちなみに部署はアメリカ、イギリス、インドだけっぽい)
破産とはなんぞや?
カードの最後の利用から120日支払いが滞ったユーザーを"破産"と見なしているらしい。
具体的には最後の使用から1年半以内に破産するかどうかを予測することになる。
学習データ期間
- 2017年3月 - 2018年3月
テストデータ期間
- 2018年4月 - 2019年4月
- 2018年10月 - 2019年10月
テストデータには開始期間が異なる二種類のユーザーが混ざっている。
公式には名言されていないが、これらのユーザーはそれぞれPBとLBに使われるユーザーに分かれている。
(Discussionで誰かが確かめていた気がする)
素性データ
さて、素性になりうるカラムは190近くあるのだが、厄介なことにすべて暗号化されている。
一応素性ごとに"D_39"とか"R_2"みたいに頭にアルファベットがついていて、これらはそれぞれ
S: Spend, 消費
P: Payment, 支払い
B: Balance, 収支
R: Risk, リスク
を表しているらしい。
正体がよくわからない素性をいじってスコアを上げていくことになるのでなかなか大変。
指標(metrics)
さて、指標であるがこれもまた厄介だった。
分類タスクであればAUCやloglossなんかが思い浮かぶが、今回は以下のMという値が採用されている。
M=\frac{1}{2}(G+D)
Gは標準化されたジニ係数というやつで、ここでは詳しく説明しないがジニ係数は
2*AUC - 1
で表せるので割とイメージしやすい。
Dは予測スコアの上位4%のうち破産を当てることができた割合を表している。
このGとDの平均を取ったものが今回の指標なのだが、これがなかなか安定しないので扱いが難しい。
さらに、PBでは上位者がみんな同じようなスコアで横並びになっていたため、自分のスコアが向上したのか分かりづらい。
例えば最後の方はPBの金圏からメダル圏外まで0.799 - 0.800が並んでいるような有り様だった。
表示上は少数第3位までなので、自分の順位の変動を見ながら小数点第四位以下で争っているような感じだった。
(自分は途中から最後までずっとPBが0.800だった)
コンペに打ち込めた期間
開始したのはコンペが中盤に差し掛かったちょうど残り1.5ヶ月くらいの時だった。
とはいえ1.5ヶ月ずっとKaggleだけに集中できたかというとそんなこともない。
(仕事だったりプライベートだったり、Kaggle以外にも人生があるので)
実際集中して取り組めた期間としては2-3週間くらいだろうか。
個人的にはこれくらいがちょうど良いタイミングだったかなと思っている。
自分がやったこと
1. EDA & 強い公開notebook (LightGBM)を写経
今回は素性がすべて暗号化されているため、EDAを通して各特徴量の分布、相関を見るのが(いつもにも増して)重要だ。
EDAに関しては↓の公開notebookが参考になった。
https://www.kaggle.com/code/kellibelcher/amex-default-prediction-eda-lgbm-baseline
スコアに関して、自分のような弱小Kagglerは無から良いスコアを生み出すのは難しいので、まずは強いnotebookを写経した。
最初の1週間くらいは公開されてた強そうなnotebookを写経しながら雰囲気を掴んだ。
このへん↓
- https://www.kaggle.com/code/ragnar123/amex-lgbm-dart-cv-0-7977
- https://www.kaggle.com/code/thedevastator/amex-features-the-best-of-both-worlds
一方で、DiscussionではLightGBMでの学習に関するかなり細かい部分まで議論されていた。
例えば乱数のseedをどの値に設定すべきかを調べ尽くして「seed=42がベストだ!」とか言ってる人もいた。
ただ、根拠なくPBのスコアだけを頼りに設定を選んでいくと過学習気味になってshake downするのが怖い。
そんなわけで、自分は最終提出はいくつかのseedでアンサンブルを取った。
2. 自分なりに素性を加える
強い公開notebookで何をやっているかというと、結局のところ
素性を加えまくってLightGBMで殴る
という脳筋パワープレイだったので、写経したnotebookをベース自分なりに素性を加える方針に。
追加素性に関しては「集計期間」を変える手法と「新しい素性を作り出す」2つのアプローチで攻めた。
具体的には
- 全期間 (1年)でなく過去1週間、1ヶ月、3ヶ月、半年で集計した素性を加える
- ユーザーごとに各特徴量のmean, max, min, lastをそれぞれの期間で計算
- 相関の高い素性同士を割り算して新しい素性を生成
- EDAがここで役に立った
- 素性の正体がわからないのでとにかく分布と相関を頼りにした
- 例えば S7/S3 は良い素性だったと思う
公開されていたnotebook(0.799)に上記の修正を加えることで一気に銀圏内(0.800)に突入できた。
3. 他のGBDTを試す + アンサンブル
上記の手法はすべてLightGBM + dartだったので、他のGBDT (XGBoost, CatBoost)も試した。
XGBoostは精度は微妙だったが、CatBoostはそこそこの精度が出たので最終的にLightGBMの結果とアンサンブルした。
最後の方に曜日、月に関する素性も加えてみたけど、これはあまり効果がなさそうだった。
(が、多様性を増やすためにアンサンブルには加えた)
最終サブでは自分の結果を1つと、強そうな公開notebookを混ぜ混ぜしたものを2つ出した。
その他設定
- CVはfold = 5で全部のfoldの平均値を用いた
- HyperParameterのチューニングはOptunaでオラっとやった
結果は銀
PBでは公開notebookを混ぜた方がスコアが高かったものの、LBでは自分のCVで出した結果の方が強かった。
やはり公開notebookはPBに過剰に適合しているものが多かったようだ。
コンペ終盤はshakeに怯えてたけど、蓋を開けてみるとそこまで大きなshake downもなくtop 3%に入ることができた。
反省点と今後
よくも悪くもGBDTで素性加えて殴ることしかしなかったため、銀圏上位までは行けても金や賞金圏には行けなかったのかなーという印象。
アンサンブルが効果的なのもあって上位はチームを組んでる人が多かったというのはあるが、ソロでも強い人は強いので、言い訳にはならないなと思った。(でもチームも組んでみたいね。誰か俺と組んで金目指そう)
(まだちゃんと見れてないけど)上位の解法を見ると工夫/実験の数が段違いなので、精進していきたいと思う。
特にNN (LSTM, RNN, Transformer)周りの解法は知ってはいるもののちゃんと使ったことがないので今後使ってみたいなと思った。
2位の解法
コンペの感想
特徴量が暗号化されてる点や指標が不安定な点など、「ややってて楽しい」タイプのコンペではなかった。
でも特にリークなどもなく無難に終わったし、いろいろと勉強になったので総合的には良いコンペなのかなと思った。
おわり!
追記: Meta featureについて
自分は試さなかった(思いつかなかったが)が、上位ではMeta featuresという素性を加えているみたいだ。
今回はユーザー単位でtargetを予測するわけなので、ログデータを集約してユーザーあたりの特徴量を計算する必要がある。
だが、最初のログデータの段階で5foldでOOFを行うことで、ログデータ1行ごとにtarget予測値を計算することができる。
(ただし、ここでは同じユーザーのログデータが同じグループになるようにfoldを行わなければならないことに注意)
そうやってもとまった1行ごとの予測値をユーザーごとに平均をとれば予測値自体をMeta featureとして使えるというわけ。
今回みたいなユーザーログを用いたコンペでは有力みたいだ。
以下のブログにわかりやすくまとまっていた。
とても勉強になった。