【ポケモン剣盾】

穴掘り兄弟の掘り出し個数の効率はどれくらい違うのか?

作成者は本ページで紹介するゲームに関して、公式とは全く関係がありません。下記のガイドラインに基づいて活動をしていきます。

ネットワークサービスにおける任天堂の著作物の利用に関するガイドライン

ご利用について(ポケモン公式サイト)

穴掘り兄弟を科学する

 ちょっとマニアックな調査事例を紹介しよう。穴掘り兄弟は、ポケモン剣盾のワイルドエリア・ハシノマ原っぱ、預かり屋付近に存在するNPCだ。私はポケモンの色違い厳選をするとき、5番道路ではなく、ハシノマ原っぱのほうを利用する頻度が高く(ちなみに2つ預かり屋の間で差はないと言われるが、どちらを利用するか派閥が存在する)、これらのNPCを目にすることが多い。彼らはW(ワット)という剣盾内の通貨を支払うことで、様々な「お宝」を掘り出してくれる。

ポケットモンスター ソード内のゲーム画像。画像内の2人の緑のNPCが穴掘り兄弟。

NPCが2人いるが、1人はスキル自慢、もう1人はスタミナ自慢を自称している。スキル自慢は、貴重な「お宝」を掘ってきてくれる代わりに掘り出し回数が少なく、スタミナ自慢は掘り出し回数が多い代わりに貴重な「お宝」は掘り出さない。剣盾が出た当初は、彼らが「きちょうなほね」や「すいせいのかけら」などを掘り出してくれるので金策として利用した人も多かっただろう。あるいは、彼らが掘り出す化石を目当てにしていた人も多かろう。

 ただ、そこで直面するのが、「彼らはすぐに掘るのをやめてしまう」(ように感じる)問題である。スキル自慢は貴重なものを掘ってきてくれるから、まあ、掘り出し数が少ないことに目を瞑ろうではないか。問題はもう1人のスタミナ自慢で、品物を一つ掘り出したところで終了することもしばしばある。本当にスタミナ自慢なのか?と感じてしまわずにはいられない。そこで、本ページでは、彼らはどれだけ掘り出し効率が違うのかを明らかにすることを目標とする。


まずは調査

 というわけで、調査を実行しよう。やることは単純で、スキル自慢とスタミナ自慢のそれぞれで100回掘り出しを行い、掘り出しごとに何個の「お宝」を掘り出したかを記録する。今回は、掘り出したものの内訳を考慮しないことにした。

 実は掘り出し兄弟には面白い仕様がある。彼らが「ふぅ……くたびれた!」というと掘り出し終了の合図なのだが、そういった束の間「いや まだだ……!」とごくたまに言い出し、掘り出しを再開してくれる。

ポケットモンスター ソード内のゲーム画像。掘り出し終了の合図。

ポケットモンスター ソード内のゲーム画像。たまにこのようなセリフとともに掘り出しを再開してくれる。

掘り出しの「再開」は複数回行われることもある。つまり、掘り出しを「再開」して、終了したのち、再度「再開」が行われることもある。この掘り出しの「再開」は扱いが面倒くさそうだ。初めの解析では、掘り出しの「再開」まで含めた合計の掘り出し数ではなく、あくまで各掘り出しの試行ごとに何個の「お宝」を掘り出したかだけに着目する。「再開」も独立な試行と考えたので、100回の調査を行ったが、「再開」が起こった分だけ調査回数は増えている。

データを眺めてみる

 得られた結果を確認してみよう。得られた中身をストレートに公開すると、なんだか問題がありそうな気がしたので、要約したものを紹介することにする。


------------------------------------------------------

library(plotn)

library(glmmTMB)


d <- read.csv("poke_dig.csv")


nrow(d[d$type == "Technic",])#スキル自慢の調査回数100回+再開分を含む

## [1] 110


nrow(d[d$type == "Stamina",])#スタミナ自慢の調査回数100回+再開分を含む

## [1] 110


mean(d[d$type == "Technic", 1])#スキル自慢の掘り出し回数の平均

## [1] 2.627273

var(d[d$type == "Technic", 1])#スキル自慢の掘り出し回数の分散

## [1] 6.180901

range(d[d$type == "Technic",1])#スキル自慢の掘り出し回数の最小値・最大値

## [1]  1 18


mean(d[d$type == "Stamina", 1])#スタミナ自慢の掘り出し回数の平均

## [1] 4.963636

var(d[d$type == "Stamina", 1])#スタミナ自慢の掘り出し回数の分散

## [1] 18.21885

range(d[d$type == "Stamina",1])#スタミナ自慢の掘り出し回数の最小値・最大値

## [1]  1 22

------------------------------------------------------


まず大きな特徴として、スキル自慢もスタミナ自慢も最小値は1となっている。0ではない、というのは特徴的で、「1個は掘り出すという最低保証」があると見える。100回以上も試行を重ねると、ごくたまに20回近い掘り出し物が得られることもあり、このデータはばらつきが大きそうであることが推測できる。実際、スキル自慢の分散は6.2、スタミナ自慢は18.2と大きい。分散は大きいが、平均はそれに比べると小さく、スキル自慢は2.6個、スタミナ自慢は5.0個となっている。

 1個掘り出すという最低保証を除去して、ヒストグラムにしたものが下図である。


------------------------------------------------------

d$number_minus1 <- d$number - 1

histn(d[d$type == "Technic", 4])#図1、スキル自慢の掘り出し回数のヒストグラム

histn(d[d$type == "Stamina", 4])#図2、スタミナ自慢の掘り出し回数のヒストグラム

------------------------------------------------------

1 スキル自慢の掘り出し回数のヒストグラム。最低保証は除いている。

。最低保証は除いている。図2タミナ自慢の掘り出し回数のヒストグラム。

得られたデータは0付近に集中しているが、ごくたまに掘り出し回数が大きい試行が存在し、ゆえにデータの分布が値が大きい方まで尾を引いていることがわかる。


データ生成のメカニズムの想起

 得られたデータからデータ生成のメカニズムを想起しよう。一番、シンプルかつ、妥当なメカニズムは、1個のお宝を「掘り出し失敗する確率」が決まっているパターンだろう。

最低保証の1個を除いたとき、掘り出し失敗する確率=pとすれば、掘り出しを成功する確率=1-pである。確率1-pを引き続ける限り、お宝は何個でも掘り出せるが、一度でもpを引けばそこで掘り出し終了である。言い換えれば、「失敗する確率pのとき、1回失敗するまでに成功する回数を記述できる確率分布」があれば、よさそうだ。これを記述できる確率分布が、負の二項分布と呼ばれる確率分布である。

 ここでは、あくまで穴掘り兄弟の効率を明らかにすることに注力するので、負の二項分布の詳しい説明は避けるが、図1、2のデータの様子からも負の二項分布の仮定は妥当そうである。すなわち、平均に対して、分散が大きく、分布が長く尾を引く点なども負の二項分布と共通である。


データの解析

 では、データを解析してみよう。解析対称のデータは、最低保証の1個を除いた値である。以下のように一般化線形モデルを使って解析を行うこととする。また、失敗確率pが変わることを仮定しないので、dispersion parameterとしてオッズ比が固定と、仮定する。


------------------------------------------------------

Tech <- d[d$type == "Technic",]

Sta <- d[d$type == "Stamina",]


fit1_1 <- glmmTMB(number_minus1 ~ 1, data = Tech, family = nbinom1(link = "log"))

#スキル自慢の解析

summary(fit1_1)

##  Family: nbinom1  ( log )

## Formula:          number_minus1 ~ 1

## Data: Tech

## 

##      AIC      BIC   logLik deviance df.resid 

##    385.3    390.7   -190.7    381.3      108 

## 

## 

## Dispersion parameter for nbinom1 family (): 2.39 

## 

## Conditional model:

##             Estimate Std. Error z value Pr(>|z|)    

## (Intercept)   0.4869     0.1376   3.538 0.000404 ***

## ---

## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1


fit1_2 <- glmmTMB(number_minus1 ~ 1, data = Sta, family = nbinom1(link = "log"))

#スタミナ自慢の解析

summary(fit1_2)

##  Family: nbinom1  ( log )

## Formula:          number_minus1 ~ 1

## Data: Sta

## 

##      AIC      BIC   logLik deviance df.resid 

##    552.5    557.9   -274.3    548.5      108 

## 

## 

## Dispersion parameter for nbinom1 family (): 3.74 

## 

## Conditional model:

##             Estimate Std. Error z value Pr(>|z|)    

## (Intercept)   1.3772     0.1043   13.21   <2e-16 ***

## ---

## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

------------------------------------------------------


得られた値のうち、今回最も知りたいのはDispersion parameterの値である。この値は、オッズ比を表し、(1-p)/p = dispersion parameterである。この結果を整理すると、p = 1/(1+ dispersion parameter)となり、失敗確率pを求めることができる。


------------------------------------------------------

1/(1 + summary(fit1_1)$sigma)#スキル自慢の失敗確率

## [1] 0.2949014


1/(1 + summary(fit1_2)$sigma)#スタミナ自慢の失敗確率

## [1] 0.2109157

------------------------------------------------------


すると、大体、スキル自慢の失敗確率は30%、スタミナ自慢の失敗確率は20%程度だとわかる。ここから正解を求めることはできないが、わかりにくい値を設定するとは考えにくいので、それぞれ30%、20%が正解に近い値なのではないかと考えられる。


------------------------------------------------------

(1 - 3/10)/(3/10)#スキル自慢の掘り出し個数平均値の推定

## [1] 2.333333


(1 - 2/10)/(2/10)#スタミナ自慢の掘り出し個数平均値の推定

## [1] 4

------------------------------------------------------


 もし、上記の推定が正しいなら、スキル自慢が掘り出すお宝の個数の平均値は(1 - 3/10)/(3/10) = 2.33個で、ここには最低保証が含まれていないので、3.33個となる。一方、スタミナ自慢の平均値は(1 - 2/10)/(2/10) = 4個、ここに最低保証を加えて5個となる。

 上記を仮定した時の負の二項分布は下記の通りで、大外れではないように見える。


------------------------------------------------------

est1 <- rnbinom(100000, 1, 3/10)#スキル自慢の掘り出し個数シミュレーション

est2 <- rnbinom(100000, 1, 2/10)#スタミナ自慢の掘り出し個数シミュレーション


histn(est1, freq = F)#図3

histn(est2, freq = F)#図4

------------------------------------------------------

3 スキル自慢の掘り出し回数のシミュレーション。最低保証は除いている。

4 スタミナ自慢の掘り出し回数のシミュレーション。最低保証は除いている。

もちろん、途中で私の憶測が入っているので、本当のところはわからない部分が多いが、大外れの推定ではないだろう。気になる点があるとすれば、スキル自慢の平均値が0.5個程度ずれており、私の実測値は「運が下ぶれていた」のかもしれないし、推定が正しくないのかもしれない。


再開も考慮

 上記の解析は、掘り出しの再開を考慮していない。これを考慮するとどうなるだろうか。まず、再開が生じる確率は下記のとおりである。


------------------------------------------------------

sum(Tech$addition)/length(Tech$addition)#スキル自慢だけで計算

## [1] 0.06363636


sum(Sta$addition)/length(Sta$addition)#スタミナ自慢だけで計算

## [1] 0.03636364


sum(d$addition)/length(d$addition)#全体で計算

## [1] 0.05

------------------------------------------------------


すると、スキル自慢とスタミナ自慢で、差があった。果たしてこの差は実態を表す差なのかは不明である。全体を使って求めると5%程度となった。判断が難しいが、私ならスタミナ自慢のほうの「再開」発生確率の方を高く設定するだろうから、この差はたまたまではないかと判断する。なので、全体で平均した5%を「再開」発生確率とする。

 「再開」も考慮した掘り出し個数のヒストグラムおよび平均値は下記のとおりである。


------------------------------------------------------

d2 <- read.csv("poke_dig_2.csv")


histn(d2[d2$type == "Technic", 1])#図5

histn(d2[d2$type == "Stamina", 1])#図6


mean(d2[d2$type == "Technic", 1])#スキル自慢の平均、再開も考慮

## [1] 2.805825

mean(d2[d2$type == "Stamina", 1])#スタミナ自慢の平均、再開も考慮

## [1] 5.150943

------------------------------------------------------

5 スキル自慢の掘り出し回数のヒストグラム。「再開」も含めた和を表示している。

6 スタミナ自慢の掘り出し回数のヒストグラム。「再開」も含めた和を表示している。

掘り出しの「再開」が起こっても、劇的に掘り出し個数が増えるわけでなく、0.2~0.3個分の効果である。

 「再開」が起こるメカニズムも掘り出しが行われる過程と同じように考えられる。つまり、「再開」が起こる確率が5%とすれば、起こらない確率は95%=失敗確率であり、1回失敗が起こるまでに成功する回数を記述する負の二項分布に従うと考えられるだろう。当然、ほとんどの場合失敗するので、成功回数は0のことがほとんどだが、ごくたまに1回や2回成功=「再開」が起こる、と考えられる。

 上記のメカニズムをもとに下記のようにシミュレーションを組んだ、「再開」はゲーム内では、掘り出し終了時に判定があると考えられるが、あらかじめ「再開」が何回起こるかを決定しておいて、「再開」が起こる回数分、余分に掘り出しの試行を行う、と読み替えてもよいだろう。


------------------------------------------------------

#スキル自慢シミュレーション

tec <- NULL

for(i in 1:100000){

  tec_tmp <- rnbinom(1, 1, 3/10) + 1 #1回目の試行における掘り出し個数、+1は最低保証

  retry <- rnbinom(1, 1, 19/20)#「再開」が何回行われるか

  if(retry > 0){

      for(j in 1:retry){

        tec_tmp <- tec_tmp + rnbinom(1, 1, 3/10) + 1

#「再開」の値分だけ、追加で掘り出す。さらにそのたびに最低保証を追加する。

        }

  }

  tec <- c(tec, tec_tmp)

}


#スタミナ自慢シミュレーション

sta <- NULL

for(i in 1:100000){

  sta_tmp <- rnbinom(1, 1, 2/10) + 1#1回目の試行における掘り出し個数、+1は最低保証

  retry <- rnbinom(1, 1, 19/20)#「再開」が何回行われるか

  if(retry > 0){

      for(j in 1:retry){

        sta_tmp <- sta_tmp + rnbinom(1, 1, 2/10) + 1

#「再開」の値分だけ、追加で掘り出す。さらにそのたびに最低保証を追加する。

        }

  }

  sta <- c(sta, sta_tmp)

}

------------------------------------------------------


 上記で得られたデータの平均値のヒストグラムは下記の通り。


------------------------------------------------------

histn(tec, freq = F)#図7

histn(sta, freq = F)#図8


mean(tec)#スキル自慢のシミュレーションの平均、再開も考慮

## [1] 3.51308

mean(sta)#スタミナ自慢のシミュレーションの平均、再開も考慮

## [1] 5.27297

------------------------------------------------------

7 スキル自慢の掘り出し回数のシミュレーション。「再開」も含めた和を表示している。

8 スタミナ自慢の掘り出し回数のシミュレーション。「再開」も含めた和を表示している。

上記のように、「再開」を考慮すると、スキル自慢は3.5個、スタミナ自慢は5.2個程度、掘り出してくれることがわかる。やはり、0.2個程度、「再開」が起こることで掘り出し個数が増えることがわかる。


まとめースタミナ自慢は確かに「スタミナ自慢」だったー

 最終的に、スキル自慢とスタミナ自慢はどれくらい掘り出し個数に差があるかというと、実測データに基づくならスタミナ自慢はスキル自慢の1.8倍程度、シミュレーションに基づけば1.5倍程度、多くの「お宝」を掘り出してくれる。確かに、スタミナ自慢はスキル自慢よりも「スタミナ自慢」だったのだ。にもかかわらず、なぜ、それを感じられないかというと、バックに潜む確率過程が影響していそうだ。掘り出し個数が従うと考えられる確率分布、「負の二項分布」は0付近の確率が非常に大きい。例え、失敗確率が小さくても、「1回失敗するまで」という制約が変わらなければ、この分布のかたちは変わらない。ゆえに、スタミナ自慢であろうと、しょっちゅう掘り出しに失敗するため、差を感じにくいのだと考えられる。