と。

統計学は趣味、マーケティングは義務。

Data Science Bowl 2019で思い切りShake downしました

なんかすごい悔しい

のでここに残すことにします。
最初はdiscussionにするかとも思いましたが、
トップ層のSolutionをみて日和ったのでここに残します。

結果はアレなんですが、個人的にはいろいろ学ぶところが多かったので、
そういうのも含めてまとめていきます。

コンペそのものの概要は雑な紹介になるのであしからず……

どんなタスク?

子供向けのゲームのログデータを使って、プレイヤーのクリア度合いを多値で分類するタスク。
クリア度合いは大きく4つ。

  • 1回でクリア→3
  • 2回トライしてクリア→2
  • 何回もトライしてクリア→1
  • あきらめた→0

多値分類でもいいが、今回は回帰問題として問いて、予測値を閾値で区切る方針が良かった模様。

どんなデータ?

ログ形式。モデルとしてはsessionごとにユニークなデータ(あるいはユーザのIDユニーク)に集計する。 event_dataという変数が、各イベントごとセルの中にjson形式で格納されていて、ここのデータを如何に上手く抽出して
特徴量にするか、というところが大きかったような気がします。

お前の結果は?

Public LBで170位でしたが、Private LBで960位でした。

参考にしたkernel

Quirck and Dirty regression

kernelはこちら 基本的にPrivateスコアでのモデルの骨格です。
各種モデルがラッパークラスとして実装されているので、ベースとしても使いやすかったです。 最終的にはこれをベースに特徴量を追加したり、モデルの回し方などを変えたりしました。詳細は後述。

Bayesian Opt Seed Blending with tuning

kernelはこちら Submitした結果では一番Privateスコアが高かったです(Private 0.548)。こっちを選んでおけば……
といっても元のkernelに特徴量追加しただけだったりするので、それで上がってもなんか運が良かっただけなので、
選ばなくて良かったなあと考えています。

Truncated train ensamble

kernelはこちら
最終的に提出したモデルで実装したtruncated CVの参考にしました。
これはtestセットが生成された過程をtrainでも再現するために使用しました。

読んだdiscussion

基本的にいっぱい読んだんですが、主にCV戦略などの話をメインに閲覧しました。
その際にあったtruncated CVのアイデアは最終的なsubmitに使う戦略でした。

やったこと

Truncated CV

Quick and Dirty Regressionをベースにしたtrainデータは、ユーザID(installation_id)でユニークではなく、session_idでユニークでした(大体17000)。
上記のようなテストデータの生成過程であることが分かったので、それを再現するためにinstallation_idをベースにランダムサンプリングして学習器に投入し、
結果を平均する形にしていました。
思えば、ここで各試行で特徴量を変えたり、foldでseedを変えたりなど、調整としてやれることはいっぱいあったなあと思いました。

特徴量エンジニアリング

ゲームのプレイログのようなものなので、プレイした日付やゲームの種類など、何かしらの特徴量で交互作用があるだろうと考え、
まずは特徴量同士の交互作用を試していました。
序盤はそれでPublic LBがそれなりに上がったので、上手く交互作用項を作れば良い特徴量になりそうだという肌感を持っていました。
結果的にAssessmentごとのGameや時間帯×曜日などはそこそこ効いたようですが、それを投入したモデルを最終的に選べませんでした……

また、公開kernelで追加していなかったevent_dataの情報を、自分で関数を組んで抜き出して特徴量に加えたりしました。
私は基本的にR言語を使っているのですが、kaggleではPythonしか使わないことにしています。理由は単純に、得られる情報量が多いからです。
ただ書くことにはそこまで慣れておらず、DSBではこれまで以上に、Forkしたkernelに妥協せず手を加えるようにしていました。
結果反省するポイントも山ほど生まれました。

Leak対策

kaggle masterのアライさんがこんなkernelを書いており、「確かに」と思って
該当する特徴量を差っ引いて検討していました。結果論的には入れていてもあまり大きな影響はなかったようでしたが、これを省いた結果でShake downの落下速度が弱まったので、
参考にしてよかったなと思います。

モデル

FoldはGroup Kfoldで、序盤は5、終盤はDiscussionの内容を参考に10にしました。 最終的にはLGBとXGBの予測値をBlendしたモデルと、LightGBM単品モデルで出しました。

他にも

  • 「クラス0」と「それ以外」を分類するモデルを作り、その予測値を特徴量に加えたモデル(private LB 0.535)
  • 「クラス0」と「それ以外」を分類するモデルと「試行回数」を予測するモデルを作り、その予測値を特徴量に加えたモデル(private LB 0.547)
  • 「クラス0」と「それ以外」を分類するモデルと「試行回数」を予測するモデルの予測値で、最終的な予測値を後処理で計算(private LB 0.487)

などを作っていました。特に3つ目は公開しています。クソ英語!!!

どうやらいくつかの段階に分けて、予測値を特徴量として入れるというアイデアは部分的に筋が良かったようでした……
ただLocal CVがあまりにも乖離していたので、この辺で選択する勇気がなかったんだろうなと思います。

やらなかったこと

いっぱい!!
例えばevent data似合った文章の特徴量化とか、evant_data内で抽出していたデータをより細かい条件で集計するとか、
できることはいっぱいありました。悔しいです。

収穫

最終的な結果は、PublicとPrivateの乖離があまりありませんでした(0.529)。 …… いいことなのか悪いことなのかわかりませんが、保守的なSubmitとしてはよい?と思っています。
また今回も私は私のCVを信じることができませんでした……Shake Downしたので、LocalのCVを信じられるように精進します。
また、(少なくともVoteの多い)公開kernelにはないアイデアを実装できたことは個人的に良かったです。
あとはこれがちゃんと精度につながるかどうかを考える脳みそがあればと思います。

課題

バージョンやSubmissionの管理がクソでした。
同じEditで特徴量追加、パラメータ変更、モデル書き換えなどを一気にやって、 どれがスコアに影響したのかがわからなくなる場面が無限にありました。
正直これに関しては何もわからないので、ここまで読んでくださった人、いろいろ教えてください……

おわりに

はやくmasterになりたい。