ProbSpace スパムメール判別コンペ参加録 - 12月 21, 2020 こんにちは、ぐぐりら(@guglilac)です。 ProbSpaceで開催されていた、スパムメール判別コンペに参加しました。 [スパムメール判別 | ProbSpace](https://prob.space/competitions/spam_mail) 参加ユーザー数:225 (うち提出ありは88)で、 public:9位 -> private: 9位 ~~でぎりぎり金トロフィー取れました!~~ (追記) [評価システム | ProbSpace ](https://prob.space/progression) の「コンペの規模」の定義が曖昧で誤解していましたが、参加ユーザー数ではなく提出ユーザー数がコンペの規模の定義っぽいので、ぎりぎり銀でした... (ぬか喜びさせないで欲しい) 前回はじめて参加したデータ分析コンペであるスプラコンペでの銀に続き、スパムコンペでも結果が出てよかったです。 過疎っていた感もあったのですが、最終週は順位一桁台の方々がスコアがどんどんあげていて順位が激動しており、しがみつくのに必死で、その辺りのスリルも味わえました。 今回の記事では自分が今回のコンペで試した解法をうまくいったもの/いかなかったものをまとめていきたいと思います。 ## コンペ概要 スパムメール判別コンペという名の通り、電子メールのテキストデータからスパム/非スパムを判別する2値分類モデルを作成するというコンペでした。 テキストデータは英語で、評価指標はF1スコアでした。 また今回のデータの特徴として、訓練データのラベル割合が偏っていることが挙げられます。 訓練データについては、非スパム : スパム = 8707 : 171となっており、少量の正例データから学習を行う必要がありました。 また、評価に用いられるテストデータのラベルの割合も公表されていて、非スパム : スパム = 7838 : 17000と訓練データと異なりスパムの方が多いという問題設定でした。 * 不均衡データへの対処法 * 自然言語処理の前処理、モデル構築などのテクニック あたりが肝となるコンペだと感じました。 以下ではこの2点について自分が試した方法を書いていきます。 ## 不均衡データへの対処 不均衡データへの対処を調べてみると、 * ダウンサンプリング * サンプルに重み付け あたりが候補で、中でもダウンサンプリング + baggingがよさそうだったので試しました。 [LightGBMでdownsampling+bagging - u++の備忘録](https://upura.hatenablog.com/entry/2019/01/12/193000) 今回は、訓練データが不均衡なだけでなく、テストデータが訓練データと大きく違ったラベルの割合であることがあらかじめ公表されているコンペだったので、こちらにも対処する必要があります。 ダウンサンプリングは通常、正例と負例を1:1になるようにサンプリングすると思いますが、今回はテストデータのラベルの割合が明らかにされている(非スパム : スパム = 7838 : 17000)ので、テストデータと同じ割合になるようにダウンサンプリングしました。 validationデータも良いCVになるようにテストデータと同じラベルの割合になるようにサンプリングしたものを使っています。 かなり思い切って負例を捨てているので大丈夫なんかなと思いましたが、baggingしているのでそのあたりはケアされているのか、結果もよかったのでこれを採用しました。CVとPublic LBも近い値になりました。 「このテストデータのラベルの割合になるようにダウンサンプリングする」というアイデアが良いかもしれないと考えた経緯に、ダウンサンプリング時のcalibrationを調べたことがあります。 詳しくは以下の記事を読んでいただきたいのですが、 [ダウンサンプリングによる予測確率のバイアス](https://pompom168.hatenablog.com/entry/2019/07/22/113433) ダウンサンプリングをして学習した際には、予測確率にバイアスが乗るのでcalibrationが必要になるという趣旨の記事ですが、これはサンプリングする前の訓練データと同じラベル割合のテストデータで評価した場合にバイアスが乗るということです。 今回はテストデータのラベルの割合がわかっている(かつそこまで不均衡ではない)ので、最初からテストデータのラベルの割合になるようにサンプリングして学習すればバイアスは乗らないじゃん、と考えました。 もしかしたら、ラベル割合が1:1になるようにダウンサンプリングして学習して、テストデータの割合に合わせてcalibrationするという選択もあるかもですが、こちらは試していません。 ## モデルや前処理 こちらでは、自然言語処理に特有の前処理やモデルについて書きます。 最終的に9位になったのはナイーブベイズとBERTのアンサンブルです。 ### ナイーブベイズ 正直コンペのほとんどの時間をナイーブベイズと過ごしました笑 今回のコンペに参加された方ならわかると思うのですが、コンペ終盤まで外部データを用いた学習済みモデルの使用禁止と規約に書いてあり、終了2週間前にBERTなどの学習済みモデルの使用許可を申請するトピックがたち、なんと許可されるというイベントがありました。 僕は最初にちゃんと規約を読んでいたので「外部データを使った学習済みモデルが使えないなんてコンペあるんだなー」なんて呑気に考えながら(データ分析コンペ初心者なので)、NNなしでナイーブベイズ一本で頑張っていました。 その結果、終了2週間前の時点でナイーブベイズ単体モデルで10位でした。 Public LBで0.985あたりでした。 ナイーブベイズで行なった工夫のうち、うまくいったもの * Bag of words + log変換 * htmlタグ、ストップワード除去 スコアが上がらなかったもの * NMFなどで次元削減 * 相関する特徴量を削除(計算が重すぎて実行できず) * ナイーブベイズの亜種を色々試す ナイーブベイズについて詳しくなりました。 色々資料読んだのでリンクをまとめておきます。 * [僕はもう、そんなにナイーブじゃないんだ - Qiita](https://qiita.com/cou_z/items/bca93fce0a08b521a3e8) * [不均衡データに対するNaive BayesとComplement Naive Bayes, Negation Naive Bayesの比較 - Debug me](https://yukinoi.hatenablog.com/entry/2016/06/07/121759) * [universalset selective NB](https://www.ninjal.ac.jp/event/specialists/project-meeting/files/JCLWorkshop_no1_papers/JCLWorkshop2012_15.pdf) * [no_bayes_no_life_nb_keep_evolving](https://www.slideshare.net/phyllo/nobayesnolifenbkeepevolving) スコアは上がらなかったですが、自分で実装して軽く実験したものもあります。 ナイーブベイズの改良版AODEを実装して実験してみる 個人的にlog変換はおすすめです。手軽なのにパッとスコアが上がったのでナイーブベイズで精度を上げたい人は試してみるといいかもしれません。 ### BERT 上で述べた通り終了2週間前に外部データで訓練した学習済みモデルの使用が許可されて、「あーどうせ俺のナイーブベイズなんかみんなのBERTで駆逐されるんだ。。。かなすいー」とか思ってコンペやめようかなと思いましたが、なんか負けた気がするしダサいので、勉強のためと思いgoogle colabで適当にBERTをfine tuningし始めました。 公開されていたbaselineを持ってきて、 テストデータのラベル割合に合わせたダウンサンプリング+ baggingはナイーブベイズと同様に使い、加えて次のような工夫をしました。 * 入力系列長を最大512に * 512を超える入力はhead-tailから半分ずつとる * 英語->ドイツ語->英語の再翻訳でデータ水増し * ハイフンの含まれた単語を元に戻す(単語の途中で改行されているもの) これらの工夫を加えて、Public LB : 0.975あたりだったと思います。やっぱり付け焼き刃ではこの程度か。。となりました。 前処理すればするほど精度が下がり、「生のデータからあんなに学習できるなんてBERTすげえ、もう俺必要ないんじゃないか」という気持ちに苛まれました。 colabのGPU上限もきて、最後の方は満足に実験できず。 どうせcolab上でしかできないし、という気持ちから使い捨てみたいなコードを書いてしまって実験管理も崩壊してしまいやりづらかったです。deepが必要なコンペにはちゃんと環境揃えてから出たいなあという気持ちになりました。 こうして、13位相当のナイーブベイズと34位相当のBERTをアンサンブルして9位、という結果でした。 ### リークしていた どこに書くか迷ったので最後ここに。 一部trainとtestに同じ文章がありました。 全く同じデータも300くらいあり、前処理してから一致判定すると1000件ぐらいありました。 予測を作ったあと、リークしているデータがあっているか見ると20個ぐらいは間違えていたのでpost-hocに直して提出していました。 ## おわりに 前回のスプラコンペで初めてコンペに出てみて、楽しかったので今回のスパムコンペにも出てみました。 途中の学習済みモデル関連のトピックで若干萎えましたが、諦めずにBERTを試したおかげでアンサンブルでなんとか9位で粘れたので、頑張ってよかったかなとは思いました。 また、やはりGPUないと実験がきついというのも身を以て体感しました...ちゃんとやるなら対処法を考えないとですね。 上位の解法の公開も楽しみにしています。 最後までお読みいただきありがとうございました。 この記事をシェアする Twitter Facebook Google+ B!はてブ Pocket Feedly コメント
コメント
コメントを投稿