Kaggle Riiid! コンペ参戦記
これは何?
- '20/10-'21/01にKaggleで開催されていた
Riiid! Answer Correctness Prediction
の参加記録です - public 51st (0.801) → private 52nd (0.802) と順位は奮いませんでしたが、現実世界での予測タスクに即したコンペの設計(後述)や、1億行を超える豊富なデータを扱えるといった内容が非常に勉強になるコンペでした。
- Discussionに投下した内容と被りますが、自身の備忘録(と解法の供養) のためにまとめておきます。
コンペ概要
ざっくり言うと
- TOEIC勉強アプリでのユーザーの正答確率を予測するコンペ
- Code Competition (コードを提出する形式のコンペ)
- trainデータは約1億、testデータは約250万。
- ただし次項で述べるようにtestデータは見ることができない
SANTA TOEIC と言うアプリが題材でした
Riiidコンペの題材はTOEIC対策アプリっぽいかな?
— ML_Bear (@MLBear2) October 9, 2020
"Santa reached No. 1 in sales among education apps in Japan and Korea." との通り、日韓でappstore 1位取ったりしてるとのこと。https://t.co/Fm1t5Owq2k
アプリLP→https://t.co/ZJhOH9Urfk
コンペの特徴: 現実世界での予測タスクに即したコンペ設計
- 特殊なサブミット方法を採っているコンペであったため、「未来の情報を用いた特徴量を作る」「超大量の特徴量で殴る」というkaggleでありがちな(実運用しづらい)方法が塞がれていたり、新しいデータに合わせて少しづつモデルや特徴量を更新することも可能だったりと、非常に実用的なコンペだったと思います。
- サブミット方法
- 提出するコードはサブミット時に指定されたAPIを叩くように書く
- サブミット後の実行時に1バッチあたり30-50問(?)程度づつレスポンスが返ってくる
- 予測を行って提出すると、次のバッチデータが降って来る。
- そのため未来の情報を使って特徴量を生成することができない
- そのバッチには前のバッチのデータの正解ラベルも与えられている
- そのため特徴量の更新やモデルの再学習なども行える
- ただし1バッチあたり約0.55sec以下で処理しないと全体の処理時間が9時間を超えてTimeout Errorでサブミットが通らない
- そのため超大量の特徴量を使うモデルは活用しづらい (testデータを受け取ってから処理するのに大量の時間を使うため)
- コンペを主催する意義も高まりそうで、この形式のコンペが今後主流になればいいなと個人的には感じてます。
これ完全に同意する。kaggleノートブックのメモリ制約とか、特徴量生成の時間制約とかも含めてRiiidはコンペの一つの完成形だと思う。テーブルコンペはずっとこれで良いんじゃないかな〜。(初心者辛そうだが…) https://t.co/zzRwOFAbka
— ML_Bear (@MLBear2) December 7, 2020
サブミット時の厳しい時間制限から、たくさんの高速化Tipsが生まれたコンペだとも思います。
pandasのleft joinを300倍以上高速化したkaggle notebook。
— ML_Bear (@MLBear2) November 24, 2020
結合するテーブルの結合キーがユニークである制約が必要なものの、軽く書き直すだけで300倍も早くなるとはすごい…!
concatのほうが速いのは直感的にわかるけどreindex知らなかったので勉強になりました。https://t.co/NFugt6Nisr pic.twitter.com/jcHK3T9ndo
概要
- 開催期間: 2020/10/06 〜 2021/01/08
- 参加チーム数: 3,406
- 目的変数: ユーザーが問題に正答するか否か (1あるいは0)
- 与えられるデータ
- ユーザーの問題回答ログ、講義ログ
- 問題ID, 問題グループID, 問題のタグID(タグ内容は非公開), 問題を解いた後に解説を見たか否か, 問題を解くのにかかった時間 など
- 評価指標: AUC
解法
- LightGBMx2 + CatBoostx1 の加重平均アンサンブル
- 特徴量は130個ぐらい
- NN (transformer) はチームメイトが終盤に試してくれていましたが間に合いませんでした
効いた特徴量
少し工夫したなやつ
回答のヤバさを図る指標
- +0.006と自分たちが作った特徴量の中では圧倒的に光り輝いていた😇
- 作り方
- train全部を使って各問題の各選択肢がどれくらい選択されているかを計算
- 例: content_id=XXXX の選択肢1/2/3/4の選択率: 9% / 5% / 1% / 85%
- 各問題で選択率を積み上げて各選択肢のパーセンタイルを算出
- 例: ↑の例だと
- 選択肢1: 15% (=1+5+9)
- 選択肢2: 6% (=1+5)
- 選択肢3: 1%
- 選択肢4: 100% (=1+5+9+85)
- 例: ↑の例だと
- 各ユーザーの過去の選択肢のパーセンタイルをAggregation(std, avg, min, etc.)
- train全部を使って各問題の各選択肢がどれくらい選択されているかを計算
- 気持ち
- ほとんどの人が選んでいないようなヤバイ選択肢を選んでる人は多分ヤバイ
- よくできる人はたとえ間違ったとしてもヤバイ選択肢は選ばないはず
- ↑の例の選択肢3とか選ぶ人は多分ヤバイのでそのあともヤバイはず
- 多分この考えは合っててstdの集計がめちゃくちゃ効いていた
少し工夫したWord2Vec by チームメート
- ややリークしていた挙動だったが+0.004ぐらい効いていてこちらも非常に効果があった
- 作り方
- 各ユーザーごとに
問題_(正解|不正解)
を並べる 問題_(正解|不正解)
をword2vecでベクトル化- ユーザーの過去N問の
問題_(正解|不正解)
のベクトルを平均してユーザーをベクトル化 - ユーザーベクトルと次の問題の
問題_(正解)
問題_(不正解)
のコサイン近似度を算出
- 各ユーザーごとに
trueskill by チームメート
- trueskillで各問題、各ユーザーの強さをスコア化
- そこからユーザーが問題に勝つ(正答する)確率を算出
- importanceは常にtopだったが+0.001ぐらい
- 最終盤に入れたため他の特徴量と食い合っていたかもしれない
- 正答の重み付き足し上げ by チームメート
- 重みは正答率の逆数として、正答を重み付きでカウント
基本的なやつ (抜粋して記載)
- 各種TargetEncoding (問題の正答率, 問題を正答できた人の割合, etc.)
- 各種ユーザーログ (過去400問の正答率, 過去400問のうち同じパートでの正答率, etc.)
- メモリの関係で過去400問だけの集計にした。800問に伸ばしてもたいして精度変わらなかったが無限にログ取ったら変わったりしたのだろうか?
- timestampのLag系特徴量
- 前に同じ問題を解いた時からの経過時間
- 前の問題からの経過時間
- timestampを加工した特徴量
- 経過時間を使う物
- 前の問題からの経過時間 / そのtask_containerにかかる平均的な時間
- 前の問題からの経過時間 / そのtask_containerにかかる平均的な時間(正答のみで集計)
- これらが効いていたのでtimestampは
問題を回答したtimestamp
かなと思っていたけどどうだろうか?
- SAINTの論文に載っていたラグタイムをなるべく再現した物
- 前の問題からの経過時間 - 前の問題にかかった時間
- 経過時間を使う物
- 単純なWord2Vec
- 各ユーザーごとに問題を並べる→問題を単語と見立ててword2vecでベクトル化
- パート別、正解の問題のみ、誤答の問題のみ、windowいろいろ振ってみる、などでたくさん作った
- パターンを足せば足すだけスコアがのびた印象
- 各ユーザーごとに問題を並べる→問題を単語と見立ててword2vecでベクトル化
効かなかったこと
まぁ大量にあるのですが不思議な点だけ
- tag
- タグの出現するパートの分布から、タグの仕分けはできていた。
- 文法のタグとかイントネーションのタグとか分かっていた
- にもかかわらず、いろいろ加工してモデルに入れてみたが全然効かなかった
- target encodingしたり、ユーザーの過去のタグの正答数とか数えてみたりした
- タグの出現するパートの分布から、タグの仕分けはできていた。
- Lecture
- 単純カウントなどをして入れてみたが全然活用できなかった
その他工夫した点
- stickytape
- コードはチームでGithub管理を行っていました。
- stickytapeを用いて、依存している特徴量生成コードなどをいい感じにまとめてkaggle notebookに貼り付けるスクリプトが生成されるようにチームメートが設定してくれました。
- BigQuery
- 学習時はBigQueryを使ってデータ生成を行い、うまく行った特徴量だけサブミット用に書き直しました
このコンペは仕事か?って思うぐらいたくさんSQL書きました
チームメイトが書いたSQLがとてもよく考えられて練られたものだったので思わずちょっと嫉妬してしまったw Kaggle仕事で使えない説を推進してる人に是非見てほしい。
— ML_Bear (@MLBear2) December 6, 2020
反省
まだ上位陣のソリューション読んでない中での反省なので読んだら変わるかもですが。
- NNを終盤までやらなかった(できなかった)
- DSB2019で上位陣がほぼLightGBM一本で上位に食いこめていた印象が強く、NNは後回しにしていた。
- サブミットコードの構築(ローカル特徴量の移植)にやや手間取って時間を食ってしまった。
- 別々に組んでいた特徴量がめちゃくちゃ食い合っていた
- みんなが作った特徴量をマージしたモデル作っても全然スコア上がらなくて控えめに言ってめっちゃショックだった。
- 単純足し上げで+0.006ぐらい見込んでいたのが+0.001ぐらいしか上がらなかった
- その時点でちょっと心折られてしまった感があった…。
- みんなが作った特徴量をマージしたモデル作っても全然スコア上がらなくて控えめに言ってめっちゃショックだった。
上位解法
- 続々と公開されるはずなのであとでまとめて記事にしようと思っています