サーモンランを機械学習しよう

Nintendo Switch

データ

SalmonStatsに登録されている約40000件のデータを参考にしました。

一シフト四人で行うので、16万人分のプレイヤーデータがあるわけですね。

ただ、水没厳正などで正しくないデータがいくつかあるので明らかにまともにプレイしていないであろうデータは除きました。

その結果、およそ15万件ほどのデータを手に入れることができました。

全プレイヤー平均値

直感的でわかりやすいのはやはり平均値でしょう。

金イクラ20.719
赤イクラ697.794
救助数1.335
ボス討伐数10.697
平均クリアWAVE数2.537
チーム平均金イクラ数83.149
チーム平均赤イクラ数2790.522
オオモノ出現数50.348
オオモノ討伐数42.794

これは途中で失敗したWAVEも含まれているので、正規化したい場合は2.537で割って3をかければオッケーです。

全プレイヤー分散

分散の値が大きければ大きいほど、人によって差がでてくるという意味です。

金イクラ144.485
赤イクラ156593.544
救助数2.214
被救助数1.917
ボス討伐数42.227
平均クリアWAVE数0.756
チーム平均金イクラ数1517.662
チーム平均赤イクラ数1378752.331
オオモノ出現数212.654
オオモノ討伐数230.865

これだけでは赤イクラなどの値が大きすぎてパッと見わからんので、標準偏差を取りたいと思います。

標準偏差はこれらの平方根を取るだけなので簡単ですね。

標準偏差

金イクラ12.020
赤イクラ369.585
救助数1.488
被救助数1.384
ボス討伐数6.498
平均クリアWAVE数0.869
チーム平均金イクラ数38.957
チーム平均赤イクラ数1174.202
オオモノ出現数14.582
オオモノ討伐数15.194

さて、平均とこの標準偏差が求まれば馴染みの深い偏差値という値を求めることができます。

が、偏差値を求めるよりも全サーモンランユーザの上位何%であるかを表示したほうが楽しいと思うのでそちらにしようと思います。

累積確率

これは自分が上位何%に位置するかを表す確率です。

例えば、上位5%だとしたら20人に1人くらいのウデマエというわけですね。

50%より上だと平均より上手いというわけなので、以前プレイしたぼくの記録を評価にかけてみました。

その結果は…

金イクラ74.394%
赤イクラ22.825%
救助数40.848%
被救助数34.414%
ボス討伐数13.384%
平均クリアWAVE数47.590%
チーム平均金イクラ数54.842%
チーム平均赤イクラ数42.386%
オオモノ出現数
オオモノ討伐数46.575%

うーん、微妙すぎて差が全然わからん!!!

ボス討伐は平均が11くらいに対して17は稼いでいたと思うのですが、伸び悩んでしまいました。

まあこれはドスコイ大量発生などで20越えの記録がたくさんあると、正規分布が広くなってしまうことが原因だとは思うのですが。

よく考えてみればこれは当然のことで、各バイトごとの記録と平均の記録を比べるのはおかしなことなんですよね。

比べるなら、各バイトの記録と自分の各バイトの記録を比較しなければいけないわけです。

多変量解析

さて、ここからが本番の多変量解析に入ります。

結局ここで求めたいのは、ユーザのパラメータのうちもっともクリアにつながっているパラメータは何で、どのくらい寄与しているかということが知りたいわけです。

多変量解析といっても「線形」「非線形」「単回帰」や「重回帰」などがあるわけですが、今回は線形回帰モデルで試したいと思います。

また、データ解析にあたりまして以下のサイトを参考にさせていただきました。

scikit-learn で線形回帰 (単回帰分析・重回帰分析)
本ページでは、Python の機械学習ライブラリの scikit-learn を用いて線形回帰モデルを作成し、単回帰分析と重回帰分析を行う手順を紹介します。 線形回帰とは 線形回帰モデル (Linear Regressi …

Pythonで回帰分析できるのめっちゃ楽、R言語とか全然わからんし…

 一部の画像がものすごくわかりやすかったので引用させてもらっていますが、権利上問題があるようでしたらすぐに削除いたします。

線形回帰モデル

  • 目的変数
    • 調べたい変数のこと
  • 説明変数
    • 入力されるパラメータ
  • 偏回帰変数
    • いわゆるバイアスというやつ
  • 誤差

説明変数と偏回帰係数の積の和で目的変数を表現するので「線形回帰」と呼ばれるわけですね。

ただ、線形回帰モデルでは複雑なモデルが表せないので、例えば各説明変数に強い相関関係があった場合には実際に欲しい値が得られない可能性があります。

今回使用したパラメータ

概要パラメータ名
金イクラ数golden_eggs
赤イクラ数power_eggs
救助数rescue
被救助数death
オオモノ討伐数defeat
チーム金イクラ数t_golden_eggs
チーム赤イクラ数t_power_eggs
オオモノ出現数t_boss
チームオオモノ討伐数t_defeat
クリアWAVEwaves

今回はこの10個のパラメータを利用しました。

オオモノ出現数とかあんまり要らなくね?と思うかもしれないけど、いろいろ試してみればいいのだ。

今回の目的関数はwavesで、要するにクリアWAVE数(0−3の値を取る)に最も寄与しているパラメータは何かということを探りたいわけですね。

線形回帰

WAVES以外のパラメータの利用

[152424 rows x 9 columns]
   Coefficients           Name
8     -0.161555       t_defeat
0      0.002392    golden_eggs
1      0.010675     power_eggs
4      0.022680         defeat
3      0.147573          death
2      0.157251         rescue
6      0.351845   t_power_eggs
7      0.395040         t_boss
5      1.378436  t_golden_eggs
-7.78419962439e-17

当たり前といっちゃ当たり前なんですが、チームの金イクラ納品数が最も重要であることがわかりました。

次点の寄与度である、ボス出現数やチーム赤イクラ数に比べて3.5倍くらい差をつけているのでこれはもう「サーモンランは金イクラをチームで運ぶゲーム」と言い切っても過言ではないでしょう。

逆に意外だったのは、個人が金イクラを納品する数というのはほとんど重要視されていないということです。

むしろ個人の討伐数は金イクラ納品に比べて10倍くらい価値が高いということが示唆されています。倒せる方は倒したほうがいいということなんでしょうか?

討伐率換算

チームでオオモノを倒した数よりも、チームでオオモノを倒せた割合の方が大事なんじゃないかと思ったので、ボス討伐率に換算して計算してみました。

   Coefficients           Name
1     -0.121819     power_eggs
0     -0.021122    golden_eggs
7      0.091203     t_boss_per
2      0.232132         rescue
3      0.247915          death
4      0.261343         defeat
6      0.396308   t_power_eggs
5      1.470474  t_golden_eggs
-1.75100735371e-15

するとオオモノ討伐率はほとんど関係ないことがわかりました。

純粋な個人成績のみ

   Coefficients         Name
2     -0.034724       rescue
3      0.366159        death
4      0.662553       defeat
1      1.248552   power_eggs
0      1.772319  golden_eggs
-1.4288863555e-17

純粋な個人成績のみを計算するとこんな感じになりました。

救助数があんまり重要視されていないのは、仲間の救助は誰でもできますが、自分がやられていると(上手いはずの)自分が行動不能になってしまうことが原因だと思います。

そして、想像以上に赤イクラが重要視されていることに驚きました。

疑問は残る

いくらなんでも金イクラのウェイトが高すぎる気がします。

何故なら、ボスを倒さないとそもそも金イクラが出現しないからです。

この係数だとオオモノを2.67体倒してようやく金イクラ1個と重みが同じということになります。つまり、オオモノ20体倒してて金イクラ20納品とオオモノを一体も倒していないけど、金イクラを30個運んだ人のほうが優秀ということになるわけです。

いくらなんでもそれはないでしょ、ということですね。

正規化してるので多分この考え方であってると思うけど、間違ってたらコメントなりで連絡下さい。

チーム金イクラ納品数は考慮してみる

   Coefficients           Name
0      0.032471    golden_eggs
2      0.219703         rescue
1      0.220199     power_eggs
4      0.242521         defeat
3      0.278942          death
5      1.652408  t_golden_eggs
-9.55042625411e-17

これだとオオモノ1体討伐が金イクラ7つ換算ということになり、この辺が落とし所なのかなという気がします。

要は、余剰分の金イクラについては価値が低く、それ以外であれば価値を高くしたいわけなんですよね。

ロジスティック回帰

クリアしたかしてないかだけであればロジスティック回帰がいいらしいので、これを利用してみることにしました。

で、ここまでやって気づいたんですが学習元のデータをちゃんと数えていませんでした()

ロジスティック回帰でやりたいことは二値分類なので、それらを同数だけ用意しないとダメなんです。

何故なら、クリアしたかどうかをパラメータから判定させたいときにクリアデータが全体の八割あれば「パラメータに関係なくクリアと判定する」という愚直な作戦が八割成功してしまうからです。

入力パラメータ

ちゃんと説明しておかないと自分でもわけわからなくなりそうなので。

金イクラ数

自身に与えられたノルマ(全ノルマの25%)に対してどのくらい金イクラを運んだかどうか。

キケン度MAXだとノルマの合計は69なので、もし69個納品すれば自身のノルマの4倍運んだことになるので4という値が得られる。

赤イクラ数

四人の平均赤イクラ数よりもどれだけ赤イクラを稼いだかという割合。

四人の平均が600のときに赤イクラ900稼げば1.5という値が得られる。

この値は重みが負なので赤イクラ “だけ” が多いリザルトは評価を悪くすることに注意。

討伐数

出現したオオモノの25%が自身が倒すべきオオモノ数として、それに対してどのくらいオオモノを倒したかという割合。

キケン度MAXだとオオモノは66体出現するので自身のノルマは約16.5体となり、この場合は33体倒せば2という値が得られる。

パラメータ重み
赤イクラ数-0.29419985
討伐数0.83772095
金イクラ数1.47840009

で、見ればわかるのだが金イクラ数が最も重みが大きいので全力で金イクラを運ぶのが正解である。

シグモイド関数

ロジスティック回帰では最終的にパラメータとバイアスの積の和のシグモイドをとるので、それを計算します。

Swiftにシグモイドを計算する関数なんてあるのかなあと思ったのですが、シグモイド関数を計算するのに必要なtanh()を計算する関数が実装されていたのでなんとかなりました。

シグモイド関数

実際に計算してみた

今のところはどのオオモノを倒したかは全然重要視されていないので、金イクラ数が少ないとオオモノをそれなりに倒しても評価が悪くなります。

ざっくばらんとしか言えないのですが、評価が90点を超えればキケン度MAXでもウェルカムくらいには上手なのではないでしょうか。

これは他の方との比較をしてみなければなんともですが…

まとめ

実際に計算してみたところ結構楽しいことが判明した。

ただ、倒したオオモノの種類などが全く検討されていないので改善は必要。

倒すのに必要な移動距離や、インク効率などで計算すればより良い評価ができるかもしれない。

記事は以上。

コメント

タイトルとURLをコピーしました