LDAを用いたカテゴリ変数からの特徴抽出
kaggleのTalkingData AdTracking Fraud Detection Challengeで1位になったチームの解法の1つである、トピックモデルを用いたカテゴリからの特徴抽出を試してみたので紹介します。
Pythonでの実装はこちらです。
概要
参考にしたのは、kaggleでの解説とリクルートコミュニケーションズさんのブログでの解説です。
やろうとしていることは、トピックモデルを考えて2つのカテゴリ変数の共起度から潜在トピックを推定し、それを新規の特徴量として用いるということです。
トピックを抽出する方法として、LDA (Latent Dirichlet Allocation) / NMF (Non-negative Matrix Factorization) / LSA (Latent Semantic Analysis) が使われていましたが、最終的にはLDAが使われていたっぽいので、今回はLDAを使います。
実際にやっていることは、上でも記載したリクルートコミュニケーションズさんのブログを見ていただければ早いです。
文章の例を挙げると、LDAでは文章の生成過程の背後には潜在的なトピックが存在し、ある文章にはそのトピックごとの重み(トピックの確率分布)が存在し、トピックには単語ごとの重み(単語の確率分布)が存在し、それらの確率分布から文章が生成されると考えます。(正確にはトピック自体もディレクリ分布という分布から生成されることを仮定しています。)
つまり、それぞれの文章がトピックの重みを持つので、トピックの重みを特徴量として使用できます。
このLDAをカテゴリ変数に適用することを考えます。
例えばカテゴリ変数として性別と都道府県があったとして、データセット内で性別ごとにどの都道府県と共に出現したかをカウントした共起行列を作成します。
つまり、性別⇔文章、都道府県⇔単語に対応させているわけです。
この共起行列にLDAを適用することで、性別と都道府県間の潜在トピックを推定することができ、性別の各値をトピックの重みの特徴量で表現できます。(トピック数を5とすると5次元の特徴量)
また、文章・単語の対応関係を入れ替えることで、同じ特徴量のペアからそれぞれ特徴量を抽出できます。(上の例だと性別を文章とみなすのか、都道府県を文章とみなすのか)
kaggleの例だと、 (ip, app, device, os, channel) という5つのカテゴリ変数から全ての組み合わせ5×4 = 20 で、トピック数を全て5にして、100次元の特徴量を作成しています。
実験
Criteoが公開しているクリック予測のデータセットを使用します。
10万件だけにサンプリングしている簡易データを以下からダウンロードできます。
各カラムの具体的な意味は伏せられていますが、最初のカラムが正解ラベル(クリックしたかどうか)、それに続く13個のカラムが連続変数、それに続く26個のカラムがカテゴリ変数です。
各行は時系列順に並んでいるので、全データの中で後ろの2割をテストデータとして用いました。
学習データ・テストデータ共に全サンプルにおける正例の割合は約23%となっていました。
比較のため、クリック予測界隈で良く用いられているfeature hashingでも実験を行いました。
LDAによる特徴抽出を行うクラスを以下に実装しています。
https://github.com/kishimoto-banana/handle-categorical-feature/blob/master/lib/topic_model.py
結果
feature hashingによるエンコードする特徴量の次元数は128としました。
LDAによる特徴抽出では、データセットにカテゴリ変数が多いので、各カテゴリ変数に対して自身を除くカテゴリ変数から3つを選択し、それらのペアに対して特徴抽出を行うようにしました。
またトピック数を3としたので、LADによる特徴抽出の次元数は26×3×3 = 234次元となります。
評価値は同じデータセットを用いたkaggleのコンペで使用されていた、LogLossを用いました。LogLossについては前回の記事を参照ください。
結果は以下のようになりました。
方法 | LogLoss |
---|---|
feature hashing | 0.647 |
LDA | 0.645 |
若干、feature hashingよりもLDAの方がLogLossが小さくなりましたが、正直コンペで1位となったほどの性能は引き出せてない気がします。
もう少し真面目にハイパーパラメータチューニングをやるべきかもしれませんが、今回はここまでで紹介に留めます。