誰も止めないので書けるだけ書く

読みやすくするように頑張ります

「リコメンド」の解体

Ashrmです。

 

この記事はゲームする部 Advent Calendar 7日目の記事です*1。このアドベントカレンダーは「ゲーム」をテーマに*2、ゲームする部Discordメンバーで記事を書いていこうという企画です。記事をまとめたポータルサイトはこちらです。

sites.google.com

昨年末に書いた記事は各所で開かれる「アドベントカレンダー」にあやかる意図があったのですが、この度実際にその手の企画に参加することになったということです。運営の皆様に感謝します。

 

 

 

 

はじめに

発狂BMSプレイヤーの方で、自分の実力の指標として「リコメンド」を用いる方は多いと思います。これは発狂難易度表・Overjoy難易度表の譜面について、LR2IRのプレイヤーのランプ状況から、各ランプの「推定難度」と「地力譜面度」を算出し、そこからこの指標を利用するプレイヤーに「推定実力」とランプが更新できそうな譜面のリコメンドリストを提示するもので、私も利用しているものです。この記事では用語の使用が雑であり、「リコメンド」が推定する「実力」を「リコメンド」と呼称したり「推定実力」と呼称したりします。

ランプを更新して「推定実力」の値を上げ、より難しい譜面がリコメンドリストに載り、その譜面をプレイし、ということを繰り返して少しずつ難しい譜面に太刀打ちできるようになる、というのが「リコメンド」利用の一つの理想形*3ですが、現実にはそれだけではあまりうまくいかず、ある程度の頻度で「リコメンド」を気にせずにフォルダ周回を行う必要があるようで、「リコメンド」との付き合い方には難しいものがあります*4

私は昨年末に書いた長い記事の中で「リコメンド」を含む、プレイデータを用いた指標の利点や難点について雑に書きました。この記事で行った計算の雑さはともかく*5、ここで私が書いた「有力な難易度表に入っているかどうかを問わずにすべての譜面を同一の体系に組み入れて選曲の参考にすることができる、譜面そのものから難易度を推定する方法の創成」という、とんでもなく理想主義的な提案はある程度の反響があったようで大変ありがたいですが、課題そのものの困難さや私自身の関心の低下などもあって、現状私はあの記事で書いた以上の考察を何もしておりません。まずリプレイデータをよく観察して、どのような理由でBADやPOORが出るかについて考察するのが一つのやり方だとは思いますが、今は自分がひたすらプレイすることにばかり集中しています。

この記事ではその問題意識とは別に、「リコメンド」を、発狂BMSプレイヤーの多くが見做すように所与の権威ある数値であるとし、「推定実力」が算出される仕組みと用語をひたすらGoogleで調べた結果から、ランプ更新と「推定実力」上昇がどのように関係しているのかを考察しようと思います。なお、高校数学程度の知識などを要求したいつもりです。

 

 

私は統計学を専門に学んでいるわけではなく、ただ発狂BMSへの関心で学んでいるだけなので、間違いがあるかもしれません。

ところで、私は4月にやや遅めのエイプリルフール的にこのような記事を投稿したのですが、この記事の内容がわかる人にとっては同じことを繰り返すような内容になります。

terrastellal.hatenablog.com

 

〇×クイズ

下の①〜④の文のうち、正しいものをすべて選んでください。

①「リコメンド」による「推定実力」計算の対象になる譜面を1つだけEASYし、残りの譜面全てをNOPLAYにしたプレイデータを用いて計算すると、推定実力の値は必ずその譜面のEASY難度になる。

②「リコメン度」が50%以上のランプはすべて、「実力」よりも「弱い」ランプなので「実力」の推定値を押し下げている。

③「リコメン度」が50%未満のランプはすべて、「実力」よりも「強い」ランプなので「実力」の推定値を押し上げている。

④「推定実力」よりも「弱い」ランプのついた譜面は、そのランプの推定難度と「推定実力」が離れていればいるほど「推定実力」を際限なく押し下げる作用があるため、可能な限り早くランプを更新すべきである。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

答えは③のみです。意外かもしれません。この記事の説明の中に、これらの理由を書いていきます。

 

項目反応理論(多段階反応モデル)

リコメンドの算出方法には「項目反応理論」が用いられています。このページの「項目反応理論」の項には推定難度を算出した方の公式の説明があります。これを読んで理解できるか見てみましょう。

walkure.net

項目反応理論がBMSのクリアと実力をどのように結び付けているかの概略がわかったところで*6、段階反応理論についてもう少し掘り下げてみましょう。

 

 

まず、先ほどの説明にあったようなクリア確率(=「リコメン度」)のグラフを、例えば★6 conflict [EX-HARD] の場合で書いてみるとこんな感じになります*7

 

ここで「クリア確率」という概念についてはっきりさせたいことがあります。この譜面のEASY難度は★4.29(b=-0.70)であり、従って「実力」が★4.29のプレイヤーのクリア確率が50%となります。しかし、これは仮にあなたの「実力」が★4.29だったとして、あなたがこの譜面をEASYゲージで10連奏したら5回くらいクリアできることが期待されるということではありません。実力が★4.29のプレイヤーを無作為に選ぶと、50%の確率でその人がこの譜面をEASYできるということです*8

★6 conflict [EX-HARD] での各ランプのクリア確率

 

これがクリア確率のグラフですが、このグラフが表しているものは「そのランプをオプションに定めたときにクリアできる確率」であり、必ずしも「プレイデータの当該譜面のランプがそうである確率」ではありません。実力推定の際、プレイデータでEASYランプがついているということは「EASYはできるがNORMAL以上はできない」という意味に取られます。段階反応モデルでは、例えば「EASYはできるがNORMAL以上はできない」確率を

 

「EASYクリア確率」ー「NORMALクリア確率」

 

としています。「ランプがEASY以上である確率」ー「ランプがNORMAL以上である確率」と言ってもよいですね*9。このような観点から、プレイデータのランプが各ランプである確率をグラフにすると下図のように、EASY、NORMAL、HARDランプに関しては山形のグラフになります。

★6 conflict [EX-HARD] での各ランプの確率


最尤推定法と対数尤度

プレイデータから「実力」を推定するには最尤推定法を用います。最尤推定法とは何でしょうか。

まず、先ほどの確率のグラフから、「発狂難易度表のプレイデータが★6 conflict [EX-HARD] のEASYランプしかない人」の推定実力を考えてみましょう*10。この譜面のEASY難度である★4.29にするべきでしょうか?

★4.29 (\theta=-0.70)の実力の人で、この譜面のプレイデータがEASYランプである確率は約37%です。ここでのEASYクリア確率は確かに50%ですが、残りの約13%はプレイデータがNORMALランプ以上である確率なので、EASYランプである確率は50%より低い37%になっています。ここでグラフを見ると、\theta=-0.7よりも\theta=-0.5でのEASYランプ確率の方が高そうですよね。実際確率が最も高いのは\theta=-0.43での約45%で、これは★5.37程度に相当します*11。★5.37でのEASYランプ確率の方が★4.29のそれよりも高いのであれば、この人の実力は★4.29とするよりも★5.37とした方が尤もらしいのではありませんか?

 

ここで、ある実際のプレイデータがあるのに対し、「実力がθである人のプレイデータがその実際のプレイデータである確率」は、そのプレイデータに対して実力がθである尤度と呼ばれ、これが最も大きいθを推定値とするのが最尤推定法です。ここまでで〇×クイズの①の文が正しくないことがわかっていただけると思います。

実際には、たいていの場合は複数の譜面のランプデータから推定するわけで、その場合は各譜面のランプに対して実力がθである尤度を計算し、それらの積がプレイデータ全体に対する尤度になって、それが最大になるθを推定実力とするわけですね。

 

各ランプが推定実力にどう影響するか見てみましょう。

FAILEDランプの尤度グラフでは、θが小さければ小さいほど尤度が大きくなるので、間違いなく推定実力を「押し下げて」います。逆にFCランプでは、θが大きいほど尤度が大きくなるので、推定実力を「引き上げて」いることがわかります*12

EASY/NORMAL/HARDランプの尤度グラフにおいて、推定実力が尤度グラフの山の左側にあるランプと右側にあるランプとがあるはずです。

 

このとき、推定実力が尤度グラフの山の左側にあるランプは、もう少し推定実力が高ければそのランプの尤度がより高くなるために、リコメンドを「押し上げて」いるということができますね。逆に、推定実力が尤度グラフの山の右側にあるランプは、リコメンドを「引き下げて」いるということができます。そして、この山の頂点は、「現在のランプと一つ上のランプの難度(=リコメン度50%地点)の平均」にあります*13。従って、ランプの難度に相当する地点は必ず尤度グラフの山の左側にあるため、〇×クイズの②の文が誤りで③の文が正しいことになります。

 

しかし、すべてのランプの尤度を掛けたものが最大になるように推定実力を決めているとなると、どのランプがどれくらいリコメンドを引き上げて・引き下げているのかが分かりにくいですね。

そこで、尤度の自然対数を取ることにします*14。すると、プレイデータ全体の対数尤度は各ランプの対数尤度を足し合わせたものになります。例えばこんな感じです。

尤度最大地点が山の頂点であり、傾きが0になっていることに注目

各ランプの対数尤度を足し合わせたものが最大となるθが推定実力になるので、どのランプがどれくらいリコメンドを引き上げて・引き下げているのかがわかりやすくなります。つまり、各ランプの対数尤度のグラフの傾き(微分係数)の総和が0になるθがリコメンドになるので、各ランプの対数尤度のグラフのリコメンド地点での微分係数が単純に「リコメンドを引き上げる力・押し下げる力」と読み替えられる量になります。この力が釣り合うところがリコメンドになるわけです。

先ほどの★6 conflict [EX-HARD] の場合は下のグラフになります。

先ほどの確率の対数をとったもの

θが小さいところや大きいところでは直線に漸近していることがわかります。FCランプやFAILEDランプで尤度1に漸近しているのは当然ですが、斜めになっている直線の傾きの絶対値は、何を隠そう地力譜面度aです*15。これが何を意味しているかというと、どんなに「実力」よりも弱いランプであっても、そのランプがリコメンドを引き下げる力の大きさは地力譜面度を超えないということです。従って、〇×クイズの④の文が正しくないことになります。また、リコメンドを引き上げる力の強弱に地力譜面度が関わっていることは直感的に見ても納得できますね。

 

さて、「対数尤度の微分」がリコメンドを「引き上げる力」・「押し下げる力」になると説明しましたが、ではリコメンドを「引き上げる力」がどれほど増加すれば、例えばリコメンドを★0.05上昇させることができるのでしょうか。実際に★0.05だけ先でのリコメンドを押し下げる力がマイナスいくつになっているか調べるのが早いですが、更新後のリコメンドの上昇量が「少しだけ」の場合は、リコメンド上昇量は更新前のリコメンドにおける「引き上げる力」に比例するでしょう。つまり、ランプ更新により更新前のリコメンドにおける「引き上げる力」がゼロからプラスに*16変化しますが、その大きさにだいたい比例してリコメンドが上昇すると言ってよいでしょう*17。それを使えば、ランプ更新に伴うリコメンド上昇量の当たりをつけられるはずです。

ところで、その比例係数はおよそ対数尤度の2回微分に反比例すると考えられます。この値(の絶対値)が大きければ大きいほどリコメンドは上がりにくくなるはずです。この「リコメンドの上がりにくさ」の挙動を見てみましょう。

FCランプの曲線はは部分的にHARDランプの曲線とかぶっています。

正直この値の変動の傾向と重要度はあまりよくわかっていませんが、リコメンドに近い推定難度のランプの影響が大きいようです。

 

脇道

Twitterを見ると、リコメンドは「フルコン力が重視される」とか「フルコンで得た偽りのリコメンド」みたいな記述が上級者を中心に見られます。これは、処理力が重視される発狂段位とは異なることが要求されているのであり、発狂段位のリコメンドの目安が曖昧になる原因になっています*18。私自身はまだそのような実力に達していないので、そういう状況が自分の感覚に染みついていないのですが、一応分かることとして、HARDとFCの難度の差が非常に大きく、多くの譜面がHARDのまま放置され、その結果リコメンドがある程度上昇してくると大量のHARDランプが大規模に足を引っ張り始めるということが起きます。そして、HARDランプが足を引っ張り始めるラインはHARD難度とFC難度の平均なので、結構FCのリコメン度が低いところから大規模に足を引っ張り始めることになります。その様子が下のグラフです。

私はこのレベルのリコメンドからまだ遠いので、このことに関して何も肌感覚がつかめておりません。

実際に使ってみた

ということで、以上のことをふまえて、私はpythonを使い、誠に僭越ながら、だいたい先に述べたような方法で自分の(beatorajaの)score.dbから自前の「リコメンド」を計算するプログラムを作り、通常のリコメンドリストに「そのランプをつけたら直近に計算されたリコメンドにおいて対数尤度の微分がいくつ上昇するか」を示す値(以下リワード)を併記し、またNOPLAYの場合はFAILEDとなってしまった場合にそのランプがリコメンドを押し下げる力(以下リスク)の大きさも記載するような表をcsvで出力するようなプログラムを制作してnか月間自分のプレイで運用してみました。

実行時に算出されたリコメンド(★、θ両方で表示)、リコメンドでの対数尤度の2回微分(=リコメンドの上がりにくさの目安)、そこから計算された★0.05上昇させるのに必要なリコメンドを押し上げる力の大きさを表示するようにしましたが、★の値やリコメン度に*19誤差があるのが観測できることもあり、あくまで参考程度といったところになります*20

得られた表はこんな感じです。

私が感じた一般の傾向を述べます。

まずNOPLAY→EASYのランプは他のランプ更新リコメンドに比べてクリア時のリワードが小さいくせにFAILEDがついたときのリスクが少量ながら存在するので、NOPLAYランプに手出ししにくくなってしまいます。しかし、NOPLAYランプの取り扱いが厄介だったのはリワードとリスクに関する情報を得る前からのことです。長期的には、地力を上げて今はできない譜面をできるようにしなければリコメンドは頭打ちになってしまい、それを防ぐためにはプレイできる譜面を増やさなければなりませんので、NOPLAY譜面にはいずれ手を出す必要があることには変わりありません。そこで、このリスクとリワードの情報をもう一度見ると、FAILEDランプを新規で1個付けるリスクはその他のランプ更新により得られるリワードよりも小さいのでFAILEDがついても他のランプでカバーしやすいという風に解釈できます。

そして、BMSのプレイごとに私が得たリワード・FAILEDで食らったロスをほとんど記録したのがこちらです。

上から、日付・譜面で得たリワード/ロスの列挙・それらの合計・リコメンドの上がりにくさ・実際にrecommend-for-beatorajaでリコメンドを問い合わせた時のリコメンド変化量。



リコメンドを押し上げる力はEASYとNORMALがHARDより弱まりやすいとはいえ、現段階ではリワードを単純に足し合わせた値と実際のリコメンド上昇にある程度相関を見ることができました。そして、★11台と★12台のリコメンドの上がりにくさの違いをより詳細に、身をもって知ることができました。

それ自体はよいのですが、この表を見ながらプレイを続けた結果あるところで思うようにランプ更新できなくなり、実力がガタガタになったと感じたためsl6とかを曲名順でランプ更新の可能性を気にしない周回を行ったところ、比較的健全な成長に戻り発狂五段に合格した(6月14日)ということです。ただの調子の波か、リングフィットアドベンチャーを最近始めたことがプラスの影響になったのか、よくわかりませんが、とにかくリコメンドを気にしすぎることなく普通にプレイする過程で更新したランプについて表を参照するのがよい使い方かもしれません。

 

おわりに

ここまで「リコメンド」の性質について述べました。リコメンドが上がりにくいことに苦しむ方は多いようですが、ランプと譜面と現在のリコメンドの組み合わせによりリコメンドを引き上げる力に強弱はあれどランプをより良いものに更新し続ければいずれはリコメンドが上がるということは初めから分かっていることです。そして、この記事の情報があればリコメンドがより上がりやすい譜面を見つけることができますが、結局クリアランプは思うようにならないので、リコメンドが上がりやすくなるというわけでもなさそうです*21。ただ、今自分がランプ更新した譜面の「リコメンドを引き上げる力の大きさ」がわかり、リコメンドがどの程度上がるかの当たりを付けられるようになるだけでも精神的には結構違ってくるのではないかと思います。

ここまでお読みいただきありがとうございました。もしかしたらこれで先述の4月1日の記事も理解できるようになるかもしれませんね。少なくとも、「リコメンド」を念頭に置いた話であるというだけで大分見やすくなるのではないかと思います。この記事は、「ランプを1つ更新するとリコメンドがどれだけ上がるか」という議論を、BMSの文脈をほぼ示さずに書いたもので、嘘ではありませんが冗談のつもりで書いていました*22。言葉の言い換え方などうまく工夫できたと思う箇所もあるにはあるのですが、結局通じなければ寒いことこの上ないので、この解説記事を書くに至りました。本記事は4月1日の記事の日本語訳に加えさらに情報を盛り込んだので、たぶんこの記事だけ読めば十分だと思います。

 

明日7月5日はiLiss.さんの記事です。

 

 

*1:順調にいけばちょうど中間地点ですね。

*2:していない人もいます。

*3:最近「リコメンド」を上げる方法としてよく聞くのが「低難易度譜面をNOPLAYのままにする」というものですが、ここでは「低難易度からプレイ埋めをして、いずれは全譜面プレイを目指す」という前提で話を進めようと思っています。

*4:私は「リコメンド」に頼る生活をするうちに、いつしか難易度感覚が崩壊してしまいました。

*5:例えば、HARDよりEASYのほうが大きな処理力が要求される譜面が多い、みたいなことを書いたと思いますが、私がBMSをやればやるほどこれは正しくありませんでしたし、記事タイトルにもあるHARDゲージの難易度比較においては、beatorajaでの強めの補正による難易度差はあるものの、実際のプレイで絶対に無視できない「空POOR」をすべて無視したことによって、計算された難易度差が適当な値よりも大きくなったらしいことを察しています。

*6:各譜面・ランプのa、bと各プレイヤーのθをどのように推定するかについては、それ自体が一つの大きな話題なのであって、この記事の範囲をはるかに超えています。少なくともプレイヤーの立場では不要な話でしょう。

*7:この記事における★とθの換算については先ほど挙げたページに掲載された換算グラフから目視で★N.00でのθを定めて計算しています。要するに昨年末に書いた長い記事の脚注19のような方法で換算したものの流用です。これで大体元のθを再現できていると思いますが、後述の通り誤差があるため、この換算を介して得られた記事中の数値をあまり信じすぎないようにしてください。ところで、★11台とか★18台でリコメンドが上がりにくくなるのはただ単にリコメンドを上げるのに必要なθの上昇量が周りの★N台にくらべて大きいことが原因の一つであり、「本質的な壁がある」という議論の有効性は弱いです。

*8:「実力が★4.29である」人は、それぞれの得意な譜面要素で強いランプをつけることができ、それぞれの苦手な譜面要素でランプをつけることができなくて★4.29になっているのであって、この譜面の要素が苦手であれば「実力」が★4.29より少し大きくてもEASYできないのです。

*9:確率がマイナスにならないために各ランプのaが同じ値になっており、推定難度がEASY<NORMAL<HARD<FCであると仮定していると私は理解しています。NORMALよりHARDのほうが簡単な譜面が十分存在し得ますが、そういう場合であってもHARDクリアをもってNORMALもクリアした扱いにするルールだと思っています。

*10:まあそういうプレイデータの人の推定実力に意味があるのかは別の問題ですが。ほかの譜面をプレイして計算対象の譜面を増やすことで、よりよい推定実力とリコメンドリストを得ることができるでしょう。

*11:実のところ、これはEASY難度とNORMAL難度の平均です。

*12:ところで「リコメンド」が「『EASY以上のランプがひとつもない』か、または『FCランプしかない』の場合に『実力』を推定でき」ない理由はお分かりになりましたでしょうか。

*13:ランプが足を引っ張り始めるのは、一つ上のランプの推定難度の方が現在のランプの推定難度よりも「実力」に近くなってからだ、と言われると、当たり前のようでもあります。

*14:というか、尤度関数は対数を取ると扱いやすいので、そうすることが多いです。

*15:こういう事実の確認は、微分してθ→±∞の極限を取るのではなく、漸近線を求める方針でやった方が計算が楽です(n敗)。

*16:FAILED埋めをしたらマイナスになります。

*17:実際には、引き上げる力はリコメンドの上昇に伴い弱まるので、上昇量は直線的な予測よりは小さくなります。

*18:私は今日発狂六段に受かった程度です。高段位者の方から見てこの記述は正しいでしょうか。

*19:リコメンドの運営さんが提供している情報では推定難度★や地力譜面度が小数第2位までの表示であることや、★-θ換算は先述のページに書かれたグラフをおよそ目視で読んでいるに等しいものであるといった理由で

*20:そもそもリコメンドが「参考程度」に扱われるための量だったんじゃ…

*21:小手先のランプ更新でリコメンドを盛ろうとするより、地力を上げるのが長期的にはリコメンドを大幅に上げられます。わかってはいるし、本来実力はなかなか上がらないものなので実力指標としてはそれで正しいんですが、地力を上げる方法論は抽象的にならざるを得ず、やはり見えるものに頼ろうとしてしまいます。慌てすぎないことが大事なのかもしれません。

*22:なんなら、使用している図も本記事のものとほほ同じだったりします。