ProbSpace 対戦ゲームデータ分析甲子園コンペ参加録 - 10月 19, 2020 こんにちは、ぐぐりら(@guglilac)です。 ProbSpaceで開催されていた、対戦ゲームデータ分析甲子園コンペに参加しました。 いわゆるスプラトゥーンコンペです。 [対戦ゲームデータ分析甲子園 | ProbSpace](https://prob.space/competitions/game_winner) 参加ユーザー数:554で、 public:44位 -> private: 47位 でぎりぎりシルバー取れました!初めてのデータ分析コンペ参戦にしては健闘できたかな? 初めてデータ分析のコンペに参加したので、その経緯や、コンペ中にとりくんだこと、振り返ってよかった点や反省すべき点などをまとめていきたいと思います。 ## 参加した経緯・目的 データ分析コンペにはもともと興味があったのですが、なかなか手が出せず、kaggleの入門記事を眺めてタイタニックを一度提出したことがあるレベルで止まっていました。 [Kaggle本](https://www.amazon.co.jp/Kaggle%E3%81%A7%E5%8B%9D%E3%81%A4%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AE%E6%8A%80%E8%A1%93-%E9%96%80%E8%84%87-%E5%A4%A7%E8%BC%94/dp/4297108437)も買って一通り眺めたのですが、実際に手を動かさないと実感がわかないなーと思っていて、テーブルコンペで良さげなコンペを探していたものの、Kaggleではちょうど良いコンペが当時ありませんでした。 そんなときにProbSpaceの方でスプラトゥーンの勝敗予測コンペがあるという情報がTLに流れてきました。 ちょうどテーブルコンペだし、スプラも結構やってるし、コンペのスタートから取り組めるいいチャンスかも、と思い参加しました。 ドメイン知識があると特徴量作成時に試行錯誤しやすそうだし、何よりモチベが続くので、即決です。 (スプラxプログラミング関連の記事もいくつか書いています。よろしければ!) * [スプラ神経衰弱アプリを公開しました](https://www.smartbowwow.com/2020/10/blog-post.html) * [スプラ神経衰弱で学ぶ!グラフ理論 - Qiita](https://qiita.com/guglilac/items/9652f210baf68c0b3c1d) * [スプラトゥーン2のブキをDCGANで生成してみる](https://www.smartbowwow.com/2020/03/2dcgan.html) 初参加なのでどこまでできるかはわからないですが、 * モデリングの各工程を一通り実践して手を動かすスピードをあげる * Kaggle本に書かれている内容を実践して定着させる という点を意識して取り組みました。 ## コンペ概要 以下のような各バトルの特徴量が与えられ、Aチーム/Bチームのどちらが勝つかを予測する2値分類のタスクでした。 (一種類の値しかとらないカラムは除外しています。) |項目名|説明| |----|----| |period |試合の時刻 | | lobby-mode |レギュラーマッチ or ガチマッチ| | mode | ルール | | stage | ステージ | |A1-weapon | プレイヤーA1のブキ | |A1-rank | プレイヤーA1のウデマエ | |A1-level |プレイヤーA1のランク| プレイヤーについては、Aチームのプレイヤー四人(A1からA4)と Bチームのプレイヤー四人(B1からB4)の8人分のカラムがあります。 加えて、トピックの中で追加データとして申請して許可されたデータも使用できました。 ブキのカテゴリーやサブウェポン、スペシャルの情報が使えました。 [API情報: ブキ (Splatoon 2)](https://stat.ink/api-info/weapon2) 他にもいくつか使用が許可されているデータがありましたが、あまり予測に使いやすくなさそうなので自分は使用しませんでした。 ## 取り組み 具体的な取り組みについて、モデルと特徴量に分けて書きます。 ### モデル LightGBMのみ試しました。 NNも試したかったですが、特徴量作成や以下で述べるモデルの構築、評価で手一杯になってしまいました。 LightGBMを使用したモデルですが、単純に各プレイヤーの特徴を並べて入力するのではなく、**プレイヤーごとに予測するモデルを訓練し、その予測値の平均が大きい方のチームが勝つと予測する**という方法をとりました。 この方法のメリットとしては、 * データ量が8倍になる(1バトルに8プレイヤーいるので) * A1-weaponとA2-weaponなどの特徴量が同じ意味を持つとモデルに教えらえる デメリットは * プレイヤーどうしの交互作用が考慮できない と考えました。 単純にこのアイデアだけで |個人予測のCV| 全体予測のLB| |----|----| |0.513|0.561| (指標はaccuracy) となり、その時点で金圏内の9位まで上がり、テンションがあがりました。 うおおスコアがあがった!(スプラコンペ) pic.twitter.com/dgdu5apFW3— ぐぐりら (@guglilac) August 27, 2020 これを受けて、この個人予測をしてから予測をまとめる方法で試行錯誤していく方針に決めました。 (他にも、例えばプレイヤーのカラムをシャッフルして水増しする、というアイデアもありましたが、トピックではあまり改善が見られそうになかったので試しませんでした。) このモデルをベースに、デメリットに挙げた「プレイヤー同士の交互作用を考慮できない問題」に対処するために、チームごとの分類器も学習して最後にあわせて予測する、というモデルに発展させたりしました。 最終的には、 プレイヤーモデルが予測したA1~A4の勝率 + チームモデルが予測したチームAの勝率 を重み付け平均してチームAの予測としています。 このようなモデルの改善や特徴量エンジニアリングのおかげでCVは57%後半までのびたものの、LBが上がらず、結局先ほど出したLBが最高スコアとなってしまいました。 CVが改善していくのにLBが下がる辛さがコンペ中にずっとつきまとい、めげずにトライし続けるのは結構大変でした。 ### 特徴量 すべて書くと大変なので、いくつかピックアップして書きます。 * mode,stage,weaponの粒度で勝率を計算して特徴量として用いる * 99, 198, 297レベルの偏りをなくす * 相手チームのレベル平均からの差を用いる * ヒーロー種のブキか * A1プレイヤーかどうか 勝率を特徴量に用いるのは、後から気づきましたがtarget encodingと同じような処理でした。 最初慣れておらず間違えてtrainデータ全体で勝率を計算して、それを特徴量に入れてモデルを学習したのでリークしてしまい、CVが66%ほどになって舞い上がりました。 初心者あるあるですね... Kaggle本を読み直し、trainデータを分割することでリークせずに勝率計算をするように書き換えました。 2点目の、「99,198,297レベルの偏りをなくす」というのは、 プレイヤーのレベル別にヒストグラムを書くと、次のように99,198,297レベルが突出して多いことがわかります。 (軸が汚くてすみません) これは、スプラではランクが99までいくとランクをリセットして1に戻すかどうかを選べる仕様になっていて、面倒でリセットしない人もいるのでレベルが99, 198, 297 (それぞれ1周目、2周目、3周目の最後)で足踏みしている、というわけです。 なので、本当はもう少しレベルが高い人もいるはず!ということで、99レベルのプレイヤーのうち、多すぎる分はレベル100以上に確率的に振り分け直す、という処理をして均しました。(確率は現状のヒストグラムに応じて重み付けする感じ) 最終的には次のようなヒストグラムになりました。 この変更も少しだけCVアップに貢献していました。 ## トピックで出ていた話題について トピックで共有されていた話題について、自分でも取り組んだものがあったのでまとめようと思います。 ### A1プレイヤーが特別? 実際にA1プレイヤーの時刻とレベル、ブキでgroup byすると確かに同じ人っぽいです。 他のプレイヤーカラムで同じことをしても、group byしてcountしても1でした。 ただ、自分にはA1プレイヤーを同定してどう予測に使うのかがピンとこなかったので、これ以上は試していません。 ### ルール別にモデルを作ると改善する? 自分の個人予測モデルをルール別に学習してみると、確かにトピックにあるようにナワバリのデータに対するスコアが高いのですが、ガチマッチと合わせて全体のスコアを出すと、一括で学習したモデルと差はないようでした。 一括で学習したモデルをを、ルール別にCVをみてみると、 |ナワバリ|ガチマッチ|全体| |----|----|----| |0.618|0.554|0.568| というように、ナワバリが当てやすいのは変わりませんでした。 ということで、最終的なモデルは全ルール共通で一つのモデルを採用しています。 ### 重複データがある? ラベルを除いて同じデータが複数ペア存在していました。 トピックでの運営への質問の回答では、同じピリオドで連戦した際に同じチーム編成で行われた試合が登録されているのでは、ということでした。 同じ特徴量のデータはペアになっていて、1ペアを除いてラベルは1か0で揃っていたので、trainとvalidに分かれたときにCVが高く出やすいという影響がありそうだったので、重複データは片方を削除しました。 重複している数は少なかったのであまり影響してなかったみたいですが。 ## ふりかえり 試行錯誤しやすい形になるようにコードを書くということは意識できたかと思いました。 プレイヤーごとのモデルと、チームごとのモデルに用いる特徴量が違うので、その辺りをうまく楽に実験できるようにしたかったので、特徴量の名前にprefix,suffixをつけることでどのモデルに用いる特徴量かを指定して、モデル側で自動で特徴量を選択してくれるように作りました。 このおかげで、特徴量作成の時はカラム名にラベルをつけてあげればdataframeをまるごと渡せば学習してくれるので、楽でした。 よくなかった点としては、実験結果の管理が乱れがちだったことです。 いつものメモのようにboostnoteを使って実験結果を管理していたのですが、すぐにわけがわからなくなってしまいました。 他の方の記事などを参考に、違う管理方法を模索したいです。 ## 気になったポイント あと気になったのが、最終的な予測を行う際に、 * CVでfoldごとの予測を出して平均する * 最後にtrainデータ全体で学習し直す のどちらが良いのか問題で悩みました。 コンペ初期の頃に実験して、後者がLBが良かったのでそちらを採用していったのですが、学習データ全体で学習し直す際にイテレーション数の調節が面倒で、ううううあああっとなりました。 (最終的にどこかのブログ記事に書いてあった、ベストイテレーションの1.1倍に設定しました) Kaggle本に書いてあったとおり、好みなのでしょうか? ## おわりに データの可視化、特徴量エンジニアリングからモデル学習、評価、 アンサンブルやハイパーパラメータチューニングなどを一通りKaggle本を参考にしながら進めることができました。 順位が上がると楽しいですが、CVはあがるのにLBが上がらないもどかしい時期がつらいですね... コンペ終了後に[13位の方の解法](https://prob.space/competitions/game_winner/discussions/Lain.-Postbc99150867f3075d7ca0)がトピックに公開されていたのですが、自分と同様にプレイヤーごとに予測するモデルを採用していました。 ただ、自分のモデルでは最後に個人予測をまとめる際に単純に重みつき平均をとっていたところ、こちらの解法ではその個人予測の結果を集計して特徴量にしてもう一段LightGBMを学習させているようでした。 自分も一度試した構造ではあったのですが、CVが上がらずにすぐにやめてしまいました。 個人予測だけでなくmean,max,min,stdなどをいれるとよかったのでしょうか。 上位の解法との小さい差がスコアの差に現れているのを見ると、悔しいですね。 また興味のある題材のコンペで参加したいと思います。 最後までお読みいただきありがとうございました! この記事をシェアする Twitter Facebook Google+ B!はてブ Pocket Feedly コメント
コメント
コメントを投稿