Kaggle「IEEE-CIS Fraud Detection」コンペに個人で参加して、2485位でした。public lb スコアだと2800位程度の提出でshake upを狙ったのですが妥当な結果に終わった次第です。
本記事では、discussionに投稿した内容を基に、本コンペでの取り組みをまとめます。良い結果ではないですが、何かの教訓になればと思います。
IEEE-CIS Fraud Detection
本コンペの課題は、user の取引データを用いた Fraud(詐欺、不正)判定でした。正例に当たる Fraud の割合が少ない不均衡データで、評価指標は AUC*1 でした。
私の取り組み
本コンペには「train, test」「public lb, private lb」がそれぞれ時系列で分割されているという難しさがありました*2。
(引用:Public/Private LB test set split! | Kaggle)
私はコンペに本格的に取り組み始めたのが終了2週間前くらいだったのもあり、public lbを追いかけないと決めていました。
最終の2サブは、保守的と挑戦的な2つのモデルです。
保守的なモデル
- Features reduced through adversarial validation
- Group K Fold
- Rank averaging of 2 models (public lb: 0.9430)
- LightGBM (public lb: 0.9432)
- Catboost (public lb: 0.9359)
挑戦的なモデル
- Features reduced through adversarial validation (Same)
- Group K Fold (Same)
- Rank averaging of 2 LightGBM (public lb: 0.9371)
- Use all training data (public lb: 0.9432)
- Use only training data of Dec 2017 (public lb: 0.8918)
Adversarial Validation
Adversarial Validation*3 を通じて、約150個の特徴量を削除しました。Adversarial Validation の AUC は1.00から0.83に減少しています。 「Microsoft Malware Prediction」のCPMPの解法*4を参照しました。
より具体的には、次の通りです。
- @kyakovlev が公開していた特徴量*5に、時間に関連する特徴量をいくつか追加
- @kingychiu の公開 Kernel*6 の設定を使用して Adversarial Validation を実行
- feature importance の高い特徴量を削除
- 手順2, 3を AUC が一定程度下がるまで繰り返す
手順2, 3は、合計で3回実行しました。
Models
評価指標が AUC だったので、アンサンブル手法として Rank averaging を利用しました。重みは「scipy.optimize.minimize」*7を使用して CV を最適化しました。
保守的なモデルでは、LightGBM とCatboost を利用しました。同じ特徴量を使っています。
LightGBMのハイパーパラメータは次の通りです。overfitting を回避する狙いがあります。Catboost はほぼデフォルトの設定です。
lgbm_params = { 'objective': 'binary', 'boosting_type': 'gbdt', 'metric': 'auc', 'n_jobs': -1, 'learning_rate': 0.01, 'num_leaves': 2**8, 'max_depth': 8, 'tree_learner': 'serial', 'bagging_fraction': 0.7, 'feature_fraction': 0.1, 'colsample_bytree': 0.5, 'subsample_freq': 1, 'subsample': 0.7, 'max_bin': 255, 'verbose': -1, 'seed': 777, 'reg_alpha': 0.1, 'reg_lambda': 0.1 }
CV Strategy
@kyakovlev の公開 Kernel*8 同様、GroupKFold を利用しました。月ごとにgroup_idを振った分割になっています。
Challenging Model
探索的データ分析を通じて、private lb のデータセットには2018年12月のデータが多く存在すると分かっていました。
sns.distplot(a=test_transaction['TransactionDT'])
そこで、2017年12月と2018年12月のデータ間では特性が類似していると考え、2017年12月のデータのみで LightGBM を学習してみました。public lb の結果は芳しくありませんでしたが、private lb で効果を発揮する可能性はあると信じ、アンサンブルに加えました。
学習データ数が少なくなっている分を補うため、Pseudo Labeling も用いています。具体的には、次のようにデータを水増ししました。
- テストデータのうち、2018年12月のデータの予測値を検証
- 予測値が0.7以上の場合は正例、0.005以下の場合は負例として追加
正例510件、負例43760件が追加されています。
おわりに
本記事では、「IEEE-CIS Fraud Detection」コンペの参加録をまとめました。
久々の Kaggle のテーブルデータコンペということで、個人で腰を据えて試行錯誤しながら取り組めたのは良かったと思います。上位の方々の解法で勉強します。
取りあえずwinner solution読むに当たって前提となるデータ仕様やコンペの特徴とか掴むくらいには取り組めたと思うので、当初の目的は果たされた。自分で手を動かしておくと、理解度が全然違う印象ある。
— u++ (@upura0) September 21, 2019