ML_BearのKaggleな日常

元WEBマーケターのMLエンジニアがKaggleに挑戦する日々を綴ります

Kaggle Days Tokyo オフラインコンペ参戦記

これはなに?

  • Kaggle Days Tokyo 2日目に開催されたオフラインコンペの参加記録です。
  • 参加88チーム中 25位(ソロ)と微妙な順位でしたが、これまでのkaggle参加の経験がとても活きて嬉しかったのと、コンペ後の懇親会が非常に楽しかったので、記録を書き留めておきます。

どんなコンペだった?

  • NIKKEI電子版のサイト閲覧ログを元に、ユーザーの年齢を推定するというお題でした。
  • 与えられたデータの種類は以下の2つでした。(情報はざっくりで書いてます)
    • ユーザーの記事閲覧ログ
      • 記事ID / user_id
      • 読了率/閲覧時間
      • 接続元情報(地域/法人IP等)
      • 接続デバイス/OS/ブラウザ/通信
    • 記事データ
      • 記事ID
      • カテゴリ/ジャンル/ラベル/キーワード
      • タイトル/本文/文字数
  • ユーザー別に記事閲覧ログを集約して、そのデータをモデルに突っ込むというのが基本戦略になります。
  • イベントログ+NLPで年齢推定という面白いお題でしたが、権利関係からか既にデータは削除されており、ちょっとだけ残念ではあります。

コード (jupyter notebook)

  • Githubにあげておきました。
  • データの内容は参加者以外に表示していいかどうか分からなかったので消してあります。予めご了承下さい。
  • 後述するように kiji_id を特徴量として使っていない点と、target encodingのやり方が怪しい点にはご注意下さい。
  • こうしたほうがええんちゃう?みたいなのがあれば何なりとご指摘下さい。

1日の流れ (ざっくり)

時間 内容 LB
(Rank)
10:30 コンペ開始!とともにサイト&WIFI激重でデータが全然DLできなくて意外とヒマw
11:00 pandas-profilingなどを使いつつデータを全体的に眺める。予想外にNLP要素が強そうでちょっと焦る。
12:30 GCPにインスタンス立上げる。ケチらずnot_preemptiveの32coresを選択。
13:00 昼ごはん食べながらベースモデル作る。ちらし寿司が美味しくて結構たくさん食べて幸せ。
13:30 毎度ながらtargetのカラム名を間違えつつ無事に初サブ 12.88
(30位?)
15:00 データ前処理しつつカテゴリ変数系を target encoding 12.55
15:30 OS/browser系を真面目に処理して target encoding 12.49
16:00 記事のメタデータ使いはじめる
16:30 記事のジャンルやラベルを target encodingで使ったらスコア爆伸びしてTOPまで0.3?差程度の9位に。
メタデータ軽く使うだけで前のサブから0.4ぐらい一気に上がったので、これワンチャンあるかな?と思って慢心する(爆)
12.05
(9位)
17:00 ジャンルやラベルのユーザー別履歴をLDA (TalkingData1st的な) 12.00
17:30 MeCab Neologd のinstallに手こずってイライラする (諦めた)
17:30 キーワードやタイトルをMecabで分かち書き → ユーザーごとに履歴取って並べてLDA 11.95
(15位前後?)
18:00 記事本文の処理を書くが重くて処理が終わらなさそうな感じが出てきてあたふたする
18:30 そのまま無事終了
(ノ∀`)アチャー
pub: 26位
priv: 25位

振り返り: 良かったこと編

事前準備がきちんと活きた

  • 普段の業務ではBigQueryでSQL芸人をしているので、pandas処理にあまり自信がありません。
  • ただ、IEEEコンペでチームメンバーの圧倒的なデータ処理能力を見せつけられていたため、SQLだと短時間勝負においてどうしても手数が劣るということはわかっていました。
  • なので、こういうの使うかな?という処理は一通り事前に書いていきました。(EloコンペでKernelコピペしてたものがあるのを思い出したので、引っ張り出して復習しつつ書きました。)

kaggleで得た知見が活きた

  • 特徴量選択(ほぼ)しない
    • 普段のkaggleコンペだと10-30個づつぐらいモデルに足してスコアが上がったら採択、ということをしています。
    • が、時間がかかることと、最終的なスコアの影響が大きくないような印象があるので、今回は作った特徴量を一部を除きひたすら足していきました。
  • parameter tuning(ほぼ)しない
    • optunaでパラメータチューニングを軽く行いましたが、手で決めたものと大して変わらなかったのでこだわりませんでした。
    • 特徴量をひたすら作るほうが時間効率が良いことが分かっていたので、迷いなく判断できてよかった。
  • 比較的トリッキーな特徴量の活用
    • トピックモデルの考えを応用して閲覧ログをLDAで分解する的なやつ
  • 並列処理計算の活用
    • コア数で殴る処理のコードを書き溜めていたので役に立ちました
  • seed averaging を忘れずにやった
    • タスクによってめっちゃ効くものもあると記憶していました (分子コンペで誰かが言ってた)
    • 軽微なスコア向上でしたが、やらないよりは全然良かった。

振り返り: 良くなかったこと編

try everything 精神の欠如

  • 時間的制約があったとはいえ、簡単にできる範囲の中でさえ try everything しなかったのは痛恨の極みです。
    • kiji_id を確たる理由もなく何故かtarget encodingの対象から外した
      • どこかで「1人にしか読まれていない記事たくさんありますねー」という言及を見ていた。
      • その言及が何故か頭に残っており「まぁなんか危なそうだし入れなくていいや」みたいな雑な理由で外してしまった。
      • これが圧倒的なMagicFeatureだったと懇親会で何人かから聞いたので、
        • 試しにLate submission用にコードを2行変更してtarget encodingの対象に入れた。すると、大幅なスコア上昇がみられた。悔しい。
          • private 11.49199 (25位) -> 11.41579 (11位)
        • target encodingのしきい値を軽く調整すれば、さらに上昇して余裕でTOP10に入れた…。死ぬほど悔しい…。
          • private 11.49199 (25位) -> 11.30513 (6位)
    • senkin-sanのカーネルと混ぜるという発想がでてこなかった。適当にaveragingするだけでそこそこの順位上昇を得られた。
      • pribate 11.49199 (25位) -> 11.45726(18位)
    • NaNカウントとかしてない
      • 過去のコンペであまり効いたことがなかった
      • 今回は効くとか効かないとか (AdversarialValidationに悪影響があるという人もいた)

チームを組まなかった

  • 記事のメタデータ軽く入れるだけで9位になったときに、これソロでもワンチャンあるんじゃね?と思ってしまった。(今思うとめちゃ恥ずかしい)
  • 終盤は作業で手一杯になってチーム組んでくれませんかーってお願いしにいく気力がわきませんでした…。

これ勉強しなきゃな、と思ってたところで躓いた。

  • 前々から、自分の target encoding のやり方はやや亜流(or コンサバ)だと認識はしていました。
    • 基本的にN件以上データある人だけ対象にしてtarget encodingを計算しています(N=500とか1000とか)
    • いつか勉強しようと思っていたが、結局勉強せず、亜流のやり方でやってしまっていました。
    • 懇親会で色々聞いていると、良い成績を残している人は当たり前のようにきちんと工夫されていて、自分との大きな差を感じました。
      • kaggle本に載っているようなFold内でFold切って計算する方法
      • weight of evidence (smoothing) の利用
      • Leave one out で計算して、aggregation時に重み付けをきちんと行う
  • 同様に、多くはないですがNNも普通に組んでる方もいらっしゃいました
    • もっと上位の極限の勝負になったら絶対に競り負けるなと思いました

戦略性の欠如

  • これはあとづけかも
    • aggregation系の特徴量は senkin-san がめっちゃ上げてくれてたので、ソロでやるなら時間の多くをNLP処理に振り切って、senkin-san のカーネルから特徴量を拝借する、とかでも良かったかも知れないです。

参考になったソリューション

時間が足りなくてできなかったものがメイン。もっと色々聞いたはずなのに2次会のワインともに脳みそから流れ出てしまっている…。

  • 閲覧ログデータごとに年齢推計→ユーザー別に集計し特徴量に
  • ユーザーがみた記事ID履歴からword2vec→閲覧記事vectorをユーザーごとに集計
  • 記事本文からword2vecモデルをスクラッチ学習 → タイトルや記事本文の解析に利用
  • 記事タイトルのTF-IDFをSVDで次元削減
  • 理解しきれなかったけど雰囲気はつかめたもの
    • 閲覧記事IDの羅列をNNに突っ込んでembedding(?)

楽しかったこと

  • めっちゃ知り合い増えた
    • 自分は雑談能力があまり高くなく人見知りもするので、立食パーティーには相当の苦手意識があります苦笑。
    • コンペやったあとだと、どんな工夫されましたか?とか比較的簡単に打ち解けられました。
    • 結果として、(当社比)たくさんの方とお話できて楽しかった。立食パーティー楽しいと思ったの人生で初かもしれないです笑。
  • コンペタスクが純粋に面白かった
    • 比較的焦ってたけど、へぇ〜こんなデータも効くんだー、とか、やっぱこれ効くよねー、とか思いながらコンペできてたので、タスクは相当面白かったと思います。

まとめ

  • オフラインコンペ楽しかったから今後も機会作って参加したいと思います。一緒にコンペで戦って(&自分をボコって)くださった皆様ありがとうございました。
  • この記事ではオフラインコンペにしか触れませんでしたが、1日目のセッションも得るものが大変多かったです。
  • このような機会を頂いたKaggle Days Tokyoの運営の方々には多大なる感謝です。(次に激アツメールきたら貢献できれば嬉しい)