先日公開した「IEEE-CIS Fraud Detection」コンペの解法*1の中で、Adversarial Validationの考え方を用いた特徴量選択について何回か質問がありました。
本記事では、Adversarial Validationの考え方を用いた特徴量選択を解説します。
Adversarial Validationとは
以前に書いた自分の記事*2から抜粋します。
いつ使う?
- TrainデータとTestデータの分布が異なる場合
- → Trainデータから適切にValidationデータを作成するのが難しい
- → Kaggleの場合、LocalCVとLBのスコアが一致しないなどの問題が生じる
解決策
- 「TrainデータかTestデータかを判定する分類器」を作る
- Trainデータを、Testデータに似ている順にソートする
- 似ている順に、Trainデータからデータを抽出し、Validationデータとする
Adversarial Validationを用いた特徴量選択
上述の通りAdversarial Validationは元来、優れた検証用データセットを構築するための手法ですが、応用方法の一つとして特徴量選択に利用する方法が提案されています。
『Kaggleで勝つデータ分析の技術』(技術評論社)*3のp.295の「Author's Opinion」にも、次のような記述があります。
逆に手元のバリデーションとLeaderboardのスコアの整合性がとれない場合に、自身の作成した特徴量のどこに問題があるのかを探る意味で、adversarial validationを用いるという使い方もできるでしょう。
CPMPさんの「Microsoft Malware Prediction」の解法
「Microsoft Malware Prediction」はPublic Leaderboardで2位だったチームがPrivate Leaderboardで1485位に転落するほど、PublicとPrivateの乖離が激しいコンペでした*4。
そんな中で、GrandmasterのCPMPさん*5とGibaさん*6のチームは、Public17位&Private6位と、両者で上位に君臨しました。
その際に彼らのチームが利用したのが、Adversarial Validationを用いた特徴量選択でした。公開されたDiscussion*7には、次のような記述があります。
With original data, it was easy to get auc over 0.98 for adversarial validation. With processed data it went under 0.7.
彼らは、Adversarial Validationの性能(ここではAUC)を0.98から0.7程度まで意図的に悪化させることで、PublicとPrivateでの特徴量が乖離している問題に対処していました。
振り返ると、Adversarial Validationの課題設定は「TrainデータかTestデータかの判定」でした。Adversarial Validationの性能が高いことは、TrainデータかTestデータかの判定が容易であること、つまりPublicとPrivateで特徴量が十分に乖離していることを意味します。
ここでAdversarial Validationの性能の悪化は、TrainデータかTestデータかの判定が難しいことを示します。特徴量の加工を通じてAdversarial Validationの性能を一定程度下げることで、PublicとPrivateでの特徴量が乖離している状態を緩和できる可能性があります。
具体的なやり方
特徴量の加工を通じてAdversarial Validationの性能を悪化させるには、特徴量の重要度の大きい特徴量を削除するという方法が考えられます。
Kaggleで頻繁に利用される「LightGBM」など、一部の機械学習アルゴリズムには学習・予測に寄与した特徴量の重要度を示す機能があります。ここで上位に来た特徴量はTrainデータかTestデータかの判定に寄与しています。一定数を取り除くことで、Adversarial Validationの性能は悪化します。
画像は自分のブログ*8から引用
Adversarial Validationの考え方は最近のKaggleのテーブルデータコンペで頻繁に実践されるようになっており、例えばこのNotebook*9には学習・予測の実行、特徴量の重要度の表示などの一連の処理がまとまっています。自身で実施する際に、ソースコードが流用できるかと思います。
単に削除するだけではなく、適切に変換するという方法もあり得ます。
例えばカテゴリ変数で、時系列的な理由でTrainデータとTestデータで登場する内容が異なる場合を考えます。このとき、この特徴量をそのまま利用してしまうとTrainデータとTestデータを分割する要因になりがちです。こういった場合は「Frequency Encoding」などでカテゴリ変数を意味のある数値に変換するといった対応が考えられるでしょう。