【IIDX】曲データの統計分析を試す【1: データ取得編】
introduction
音ゲーの曲ごとの難易度差を推定したりといった事柄は既に多数実施されている。
例えば、beatmania IIDX(以下IIDXとする)のLv12の曲は現在300曲以上存在するが、これらがすべて同一の難易度というわけではない。
他のゲームでも似たような状況であるが、IIDXの大きな特徴は
同一難易度間の差が大きい
ことが挙げられる。端的に言えば、難易度表記が仕事をしていないことになる。
未プレイの方にわかりやすく言うなら、カレーの辛口ぐらい信用ならない表記である。
このような現状であるため、有志によってLv12間での非公式難易度表というものが作成されている。
しかし、これらの表はあくまで多数決で決定されるものであるため以下の問題点が存在する。
- 少数意見が反映されにくい。
- 「地力」「個人差」という2つの指標しか存在しない。
- 現状Lv12しか対象でない。
これらの問題を解決できる画一的な方法を模索するため、データ取得および統計処理によって楽曲難易度を計算してみたい。
また、楽曲スコアについても計算をする予定である。
…というのが建前で、本音としては統計処理学習のいい題材だからである。
本記事は主にデータの取得に関する記事である。
次の記事はこちら。
【IIDX】曲データの統計分析を試す【2: IRT編】 - analytics-arkのブログ
method
取得方法
ライバル機能によって、他人のプレイ状況を確認する機能が公式サイトに備わっている。
その機能を使用することで、対象となる全プレイヤーの曲クリア状況を取得した。
取得対象
【IIDX Rootage】の【八段~皆伝のプレイヤー全員】の【Lv11, Lv12のクリア状況】。
上記を対象とした理由としては以下の数点がある。
対象バージョンがrootageである理由
現行バージョンでは中伝/皆伝が未解禁である(19/12/08現在)。
また、新曲に関してはプレイ状況がまちまちであると考えられるため、バージョン移行前のrootageを対象とした。
取得範囲を狭めている理由
何も範囲を狭めずとも、全員分取得すれば間違いがないと思われる。
しかし、現実には取得時間の関係から全取得は困難となる。
上記の範囲のデータを取得するだけでも3日ほど費やしている(メンテで接続できない時間込み)。
これ以上範囲を広げると相当の時間がかかってしまうため、狭める必要性が生じている。
八段未満を対象に含めない理由
八段を取得するメリットが大きいため。
段位による選曲制限が存在するため、(取得可能な)殆どのプレイヤーは八段を取得する。
八段を取得しない(できない)ユーザーはLv11をクリアできない人がほぼ全てである。
八段を対象に含める理由
九段以上を取得する旨味があまりないため。
上級プレイヤーでも八段だけ取得する人がいる。これらのデータを無碍にするのは勿体ないため。
対象Lvが11,12である理由
Lv10は曲数が非常に多く、hyper/anotherが混在していることから全てをプレイしている人は限られている。
一方、Lv11以上は曲数があまり多くないため、上達の過程で必然的にある程度プレイされる傾向にある。
また、全白(全曲HARDで埋めること)が多く報告されるのもLv11以降となる。
これは「曲が多くない」「難易度が比較的高い」ことから、やりこみの対象として適しているためである。
これらの性質から、調査対象とするのはLv11以上が妥当と考えた。
取得プログラム
使用言語
今回はnodejsを使用した。
使い慣れているのと、puppeteerを使うのに都合が良いと考えていたためである。
cookie取得
まず、ライバル機能による曲データの閲覧にはe-AMUSEMENTのベーシックコースに加入する必要がある。
そのため、手持ちのアカウントで加入する。月330円也。
次に、e-amuログイン情報を維持していないとコンテンツの取得ができない。
なので、cookie取得プログラムを書く。
今回はpuppeteerを使用し、いつものUIでログインをすることでcookieを取得することにした。
プレイヤー一覧取得
cookieさえ用意できれば、あとはHTMLを取得しそれをパースすればよい。
といってもパースが若干面倒なのでcheerioを使用する。
(良くも悪くも)jQueryライクに記述できるので、実際にjqueryを扱っているのとそんなに変わらない。
まず段位の一覧を取得し、ついで各段位のユーザーを全て取得する。
この際ログインしたcookieが存在しないとrivalHashが取得できないので注意。
またrivalHashはcookie固有の値ぽい(ログインし直すと変わる)のでそこも注意。
HTMLをパースしてるコードはこんな感じ。一応rootage/heroic verse両対応。
MySQLに以下のテーブル構造を用意し、保存した。
プレイ状況取得
同様にパース処理を行っていく。該当箇所のコードはこのようになる。
今作(rootage)のNOPLAYでスコアがない曲についてはNULLを代入するようにした。
テーブル構造は以下の通り。
取得処理
プログラムを書いたら後は実行して集まるのを待つのみである。
対象となるプレイヤー(八段~皆伝)は35728人。
ちなみに全プレイヤー(7級~皆伝全て)は62334人なので、だいたい6割である。
また、1人あたりプレイ状況の取得に5-8秒程度ぐらいかかる。
つまり、全取得には丸2日ぐらいかかる計算になる。
result
まずデータを取得できたか確認する。
SELECT COUNT(DISTINCT iidxId) FROM `playstates` WHERE 1
これはユーザー総数(35728)と同じ数である。全ユーザー分を取得できていそうである。
次に、簡単なSQLを実行して個別取得がうまくいっているかを確認する。
AAのAのAAAを成し遂げている人のデータを取得してみよう。
SELECT songName, songDifficulty, djLevel, COUNT(djLevelId) FROM `playstates` WHERE songName = "AA" AND songDifficultyId = 3 AND exScore > 0 GROUP BY djLevelId, songDifficulty, djLevel ORDER BY djLevelId ASC
実行結果は以下のようになる。
割といた。
未プレイは除いているのでバイアスはかかっているが、既プレイ全体の15%程度はいる。
summary
取得には成功した。しかしクエリの実行時間がちょっと長い。
それはそれとして、上手い人多いなあ…
Next: