Tak's Notebook

Kaggle, Machine Learning, Data Analytics

Kaggle IEEEコンペ 上位解法まとめ

f:id:takaishikawa42:20191007061742p:plain

目次

IEEE コンペ

  • クレジットカード等の取引(Transaction)履歴のデータから、その取引が詐欺(Fraud)かどうかを検知するタスク
  • ホストによってあらかじめ特徴量エンジニアリングされた列が追加されているが、ほとんどすべての列が匿名化されている
  • コンペ序盤に匿名化された取引時間列から、学習データとテストデータの期間が半年ずつで時系列になっている

所感

上位陣に共通しているポイント

  • ユーザーIDを特定する
  • 学習データ中のユーザーIDとテストデータ中のユーザーIDの被り率は低いことを見つける
  • ユーザーIDはそのまま用いず、集計値に変換して用いる。ユーザーIDの特定に寄与するような特徴量も直接用いない
  • あるユーザーIDが一度 Fraud とされると、その後も Fraud とされるパターンを見つけて後処理を行う

異なる点

  • ユーザーIDの定義の仕方はチームによって異なっていたが、いずれももっともらしいユーザーIDを定義して特徴量生成に役立てていた。
  • コンペ終盤の伸び悩んでいた時期にユーザーIDを特定することでスコアを一気に押し伸ばすことができたというチームもあれば、序盤から特定していたチームもいた。
  • ユーザーIDの特定によって予測値を特定できることを利用して Psuedo-labeling を行うチームが多く見られた
  • モデルの Blending は Lightgbm を基本として、Catboost を組み合わせるパターンが多かったように思われる。

1st Place Solution

チーム

  • 2人チーム

リンク

IEEE-CIS Fraud Detection | Kaggle

IEEE-CIS Fraud Detection | Kaggle

要点

時間特徴は重要でない

  • 時系列データだが時間は重要ではなく、むしろ未知の顧客の Fraud 検知問題であると捉えるべきである。
    • プライベートテストデータ中の68.2%が学習データに含まれていない顧客であるため。

f:id:takaishikawa42:20191007062622p:plain
各青線はユニークな顧客IDを表す。x軸は経過日数を表す。縦の黒線は学習の終了日、パブリックテストの開始日、プライベートテストの開始日を表す。

Magic Feature

  • 一度顧客が Fraud 判定されれば、そのアカウント全体が Fraud とされる(ホストのコメント)。そのため Fraud な顧客を予測する必要がある。ホストは120日後には Fraud のラベルが外されると言っているように思われたが、学習データ中にそのようなデータは殆ど見られなかった。
  • 取引2回以上のクレジットカードの96.9%が Fraud=0 で、2.9%が Fraud=1 で、0.2%が両方ある。

Fraud な顧客

  • 顧客IDは(ユニークな顧客を特定するのは) card1, addr1, D1 の組み合わせで決まる。D1 は顧客(クレジットカード)が取引を始めてから経過した日を表すので、 Transaction_Day - D1 によってクレジットカードが始まった日にちが分かる。同様に、 Transaction_Day - D3 によって直近の取引日が分かる

f:id:takaishikawa42:20191007063147p:plain

過学習の防止

  • 過学習を防止するために顧客UIDは用いず、また顧客を特定するの役立つようなD, V, ID 列は用いなかった。(学習データ・テストデータの Adversial Validation で Lightgbm の特徴重要度を見ることで分かる)
  • プライベートテストデータの68.2%が学習データにないので顧客IDを特徴量に使えなかったが、代わりに df.groupby("uid")[CM_columns].agg(["mean"]) によって集計値を取り、 uid を用いなかった。

詳細

Final Model

  • Catboost, Lightgbm, Xgboost の3モデルを組み合わせたもの。
  • 選択した Submission は CB, XGB の予測値を LGB に加えたもの、もう一つは単純な平均値を取ったアンサンブルモデルである。両方の Submission とも、単一の Transaction しか持たない顧客に関しては全予測値の平均値に置き換える後処理を行って、LBスコアで0.001上昇した。

UIDの見つけ方

EDA

Feature Selection

  • 以下の手法を用いながら特徴選択した
    • forward feature selection (using single or groups of features)
    • recursive feature elimination (using single or groups of features)
    • permutation importance
    • adversarial validation
    • correlation analysis
    • time consistency
    • client consistency
    • train/test distribution analysis
  • time consistency とは一つの特徴量あるいは特徴量のグループを用いたシングルモデルで学習データの最初の一ヶ月を学習し、学習データの最後の一ヶ月を予測した。
    • これによって特徴量自体が時間に対して一貫性があるかどうかを評価できる。
    • 5%の特徴量がモデルの精度を下げた。これは現在において存在するが将来においては存在しないパターンが、いくつかの特徴量には存在することを意味する。

Validation Strategy

  • 様々な Validation 戦略を試した。
    • 最初の4ヶ月を学習、1ヶ月をスキップして、最終月を検証データとする
    • 最初の2ヶ月を学習、2ヶ月をスキップして、最後の2ヶ月を検証データとする
    • 最初の1ヶ月を学習、4ヶ月をスキップして、最終月を検証データとする
    • month を group として GroupKFold で CV を行った
    • また UID を使って既知・未知の顧客をどの程度分類できるモデルかどうかも分析した

2nd Place Solution

チーム

  • 5人チーム

リンク

IEEE-CIS Fraud Detection | Kaggle

要点

Data Cleaning

  • 生の特徴量と Frequency Encoding で学習データとテストデータの分布を見て、全ての特徴量をスクリーニングした。 card1 の例を以下に示す。(左が生データ、右がエンコーディング済みデータ。赤が学習データ、青がテストデータ。左のx軸は card1 、左上のy軸は頻度、左下のy軸はログ変換したターゲットの平均で0は学習の平均。右は、x軸は card1 の頻度をログ変換したもの)

f:id:takaishikawa42:20191007063218p:plain

  • card1 の値の多くはテストデータにのみ現れることが確認できるので、これをそのまま用いると Private LB で大幅にスコアを落とすことになる。そのため Frequency Encoding した値を用いた。

CV

month を使って以下のように fold を切った。(初月を0とする)

0 | 2 3 4 5 6
0 1 | 3 4 5 6
0 1 2 | 4 5 6
0 1 2 3 | 5 6

この方法で特徴量、ハイパーパラメータチューニング、特徴量選択を評価した。

Feature Engineering

  • 全ての特徴量に対して Frequency Encoding を行ったうえで、上記の CV 方法で Lightgbm を用いて Permutation Importance を行った。ただし、上記4モデルの全てでスコアが改善しなかった特徴量のみ保持することにした(Permutation Importance ではスコアが上昇する=意味のない特徴量のため)
  • uid は以下のようにして特定した
data['uid1']` =  (data.day - data.D1).astype(str) +'_' + \
            data.P_emaildomain.astype(str)
data['uid2'] =  (data.card1.astype(str) +'_' + \
            data.addr1.astype(str) +'_' + \
            (data.day - data.D1).astype(str) +'_' + \
            data.P_emaildomain.astype(str))
  • ユーザーID は過学習を起こしうるので、直接特徴量として用いなかった(しかし Late Submission で CB に uid を加えたところベストスコアを記録した)。代わりに、 uid を用いて集計値を取った。
    • uid1, uid2 それぞれで groupby して、 transactionDTtransactionAmt の直近値との差(shift で算出)・平均値・標準偏差・中央値を算出する
  • その他、 uid を用いて Target Encoding した特徴量のうちいくつかはスコアの改善に寄与した。

Final Blend

  • Lightgbm のほか Xgboost, Catboost を用いた
  • 後処理として、ある時点で Fraud とされたカードは将来の時点でも Fraud とされることに注目して( Lag 変数を注目することで気づいた?)、予測値を馬が帰することで PublicLB で0.001上昇させた。

6th Place Solution

チーム

  • 5人チーム

リンク

IEEE-CIS Fraud Detection | Kaggle

要点

User IDs

CV

  • 月ごとに time-split すると、時間を経過するごとにユーザーIDのカバー率が低下していくので、学習データ中に含まれているユーザーIDがテストデータ中にある場合と、そうでない場合に分けてモデルを作ることに注力した

Features

  • あまり時間を割かなかった。多くの Count Encoding や Aggregated Features を用いた。また、UID ベースの集計値を用いた。

Models

  • LGB, Catboost, NN を月ごとに分割したCVベースで学習させた。Catboost では ID列 をカテゴリカル変数として含んで学習させた。UID を用いて確実に Fraud だと分かるデータを用いて Psedo-labeling を行って Lightgbm を学習させた。

Blending

  • 全体的な CV スコアを最適化するより、UID が被っているか否かで別々に最適化させた。
  • 基本的には生の確率値の平均値を取った。
  • ランクベースのブレンディングも行った(詳細イマイチ理解できず)。

Post-processing

  • UID ごとに予測値の平均値をとって、その値で予測値を置き換えた。

Final submission

    1. Blending モデルのうちスコアの高いものをさらに rank-average で Blending した
    1. month の代わりに UID ごとにCVを分割したモデルを用いた

9th Place Solution

チーム

  • 2人チーム

リンク

IEEE-CIS Fraud Detection | Kaggle

要点

ユーザーID

  • ユーザーIDの特定
  • "2017-11-30" + TransactionDT - D1 がユーザーを特定するのに最も有効な特徴量だった。同様のことを他の D 特徴量にも行った
  • ユーザー特定を確認するために V95, V97, V96 あるいは V126, V128, V127 が有効だった。前者はそれぞれユーザーごとの前日、前週、前月の取引回数であり、後者はそれぞれユーザーごとの前日、前週、前月の TransactionAmt の累積和である。
  • ユーザーID情報を特徴量として用いることもできたが、後処理で Psuedo−Labelling に用いた

CV

  • CV設定は学習データセットの最初の3ヶ月を学習データに、最後の2ヶ月を検証データにした(間の1ヶ月は不使用)。Public LB と良く相関したが、Pribate LB では Shake down する形になった。

Model

  • モデルは Lightgbm, Catboost, Xgboost を使用した。

11th Place Solution

チーム

  • 5人チーム

リンク

IEEE-CIS Fraud Detection | Kaggle

要点

モデル

  • 解法は Stacking ベースのもの。20個のモデルを Stacking することから始めて、どんどんモデルを追加していった。追加したモデルは以下の通り
    • Public Kernel の大半
    • LGBMモデル: カテゴリカル変数と Numerical 変数をPCAしたデータを用いた
    • XGBモデル: カテゴリカル変数を様々な方法(Target, Catboost, Weighted of evidence?...)で Encoding したものと生の Numerical 変数で学習させた
    • Lasso: 平均値・中央値で欠損値補完した Numerical 変数を用いた
    • Ridge: 平均値・中央値で欠損値補完した Numerical 変数を用いた
    • LGBM/Lasso: Count Encoding した
    • LGBM/Lasso: Count Encoding + One-hot Encoding
    • Gaussian Naive Bayes: Count Encoding
    • Multinomial Naive Bayes: Count Encoding
    • Univariate LR: スピアマンの相関係数でターゲットとの相関が高い V 特徴量を選択して用いた
    • LGBM/XGB: カテゴリカル変数と、コルモゴロフ・ミルノフ検定で選択した いくつかの Numerical 変数
    • NFFM/FFM: 生のカテゴリカル変数とコレを使った Numerical 特徴量
    • LibFM: このコードを用いたカテゴリカル特徴量
    • Catboost: カテゴリカル変数と Numerical 変数をすべてカテゴリカル変数としてモデルに与えた
    • NN: 異なるアーキテクチャで生のデータを学習させた(カテゴリカルデータを Embedding したのと、異なる欠損値補完手法を適用した Numerical 変数)
    • LGBM/XGB: カテゴリカル変数の二次、三次、四次の組み合わせ特徴量を用いた
    • Extra-Trees Classifeir: Numerical 変数を PCA したデータを用いた
    • KNN: 少数の Numerical 変数を用いた
  • 最終的に900くらいのモデルができたので、LightGBM を classifier に用いて RFE(Recursive Feature Elimination)によって120くらいモデルを選択したところ、LB で 0.9552 まで上がった。
  • その他、bruto force で集計値を取って2000個の特徴量を用いた XGB や、month で GroupKFold したバリデーションベースの FE を行ったデータで学習させたりした。
  • ユニークID として card1 + card6 + addr1 + addr2 + date.day - D1 を使用して FE したモデルでは 0.9649 までスコアを伸ばした。
  • ベストモデルは190このモデルから5回 XGB でバギングしたモデルで、CV: 0.9644, LB: 0.9650 だった。

13th Place Solution

チーム

  • ソロ

リンク

IEEE-CIS Fraud Detection | Kaggle

要点

1. Validation Scheme

  • 最初はシャッフル無しの 5fold CV を用いた。
  • コンペ後半ではシンプルな time-split で学習データの後半10万件を検証データとした。
    • 5fold CV は時間がかかりすぎるため.
    • 5fold CV で作られる重要な特徴量はリークを引き起こしたためでもある。

2. Reconstructing user_id

  • isFraud=1 のデータを注意深く見ると、非常に似ているデータの多くのクラスターが存在していることに気づいた。Home Credit でも同じようなことを経験していたため、bruto force アプローチで D 特徴量とカード情報から様々な user_ids を作成した。

3. Feature Engineering

  • user_ids を用いて様々な特徴量生成を行った。生成された特徴量の多くの中でも、過去のデータに対する Seq2Dec と Target Encoding が CV と LB の両方でかなりの改善が見られた。
  • Seq2Dec は個別のトランザクションエンコードするのに良い手法だと考えている。というのも、順序情報の損失を防ぐことができるのと、様々な長さの系列を扱うことができるためである。さらに、典型的な特徴量も足した(count, share?, user_id の系列の個数, user_id が最初に出現してからの経過日数, user_id が直近で現れた日からの経過日数等)

f:id:takaishikawa42:20191007063639p:plain
Seq2Dec

4. Modeling and Blending

  • モデルは Lightgbm と Regularized Greedy Forest(メインは Lightgbm)
  • Seed Averaging と Seq2Dec / Target Encoding の際に異なる n_folds でバギングしたモデルによってモデルの多様性を増やした

5. Result

  • 13th / 6831 teams
  • Public LB: 0.965086, Private LB: 0.941338

15th Place Solution

チーム

  • ソロ

リンク

IEEE-CIS Fraud Detection | Kaggle

要点

CV

時系列データのため unshuffled KFold を用いて予測した。学習データの最後の20%をホールドアウトしておき、最初の80%のデータをすべて使ってモデルを作成した。このCV設定に沿って、特徴量生成・パラメータチューニング・後処理を行った

モデル

  • Lightgbm のみを用いた
    • Catboost も NN も良い精度が出なかったため。
  • Final submission は 4~5 個の Lightgbm モデルの重み付きブレンディングしたもの
  • 特徴量選択はいずれの手法もCVスコアを下げたので行わなかった。

User ID

  • 異なる特徴量の組み合わせに基づくいくつかの User ID 候補を作成した。それから学習データ内で isFraudshift(1) した後に Target の平均を計算することで その質を検証した。具体例は以下の通り。
train['ReferenceDate'] = train.DayNumber - train.D1

key_cols = ['TransactionAmt','ProductCD','card1','card2','card3', 'card4','card5','card6','addr1','addr2','ReferenceDate','P_emaildomain']

train['key'] = train[key_cols].apply(tuple,1)

train['previous_isfraud'] =  train.groupby(['key'])['isFraud'].shift(1)

print(train.groupby('previous_isfraud')['isFraud'].mean())
>previous_isfraud
>0.0    0.000528
>1.0    0.991961
  • 学習データで得られた同一ユーザーID情報をテストデータに用いる後処理をすることでスコアが大幅に改善した。

Feature Engineering

  • Userid ベースの多くの集計特徴量を作成した
  • 予測値の平均をユーザーIDの全てのトランザクションに適用した。これもスコアの大幅な改善に役立った(高精度に予測できていたユーザーIDにのみ適用した)。

Blending

  • LGBM の dart メソッドが良かった
  • Blending による予測値はテストデータにのみ出現する新しいユーザーIDにのみ適用した

詳細

EDA

  • TransactionAmt や カード情報でソートしてエクセル上でデータセットを分析した。そのときに シフトした isFraud とターゲット値の isFraud に高い相関があることが見て取れた(エクセルでデータを見ることはかなり有用だった)
  • D1, D3 列が意味することに気づいた。それから data['DayNumber'] - data['D1'] によってReferenceDate 特徴量を作成することができた

特徴量生成

  • 異なる特徴量の組み合わせによって Userid を作成することと、シフトした isFraud 情報を後処理で用いることから始めた
  • ユーザーIDベースの集計特徴量を作成した

CV

  • モデルが同一ユーザーを探して分類するだけになっていたので、テストデータにしか存在しない新しいユーザーを予測できなかった。実際に学習データを8:2に時系列で分割してユーザーごとにAUCを見ると、既存ユーザーは0.9777になる一方、未知ユーザーの場合は0.900にしかならない。
  • 結果的に unshuffled KFold からユーザーIDベースの GroupKFold に変更した
  • 既存ユーザーの予測値はそのままにして、未知ユーザーの予測に対してのみブレンディングした予測値を適用した。