スプラトゥーン2の勝率とウデマエアップ (負の二項分布)

スプラトゥーン2では、プレイヤーのうまさをウデマエというランク(C-, C, C+, B-, ..., S+9, X)で表します。

ウデマエはガチマッチで勝つことで、ウデマエメーターがたまっていき、満タンまでたまれば上のランクにウデマエアップします。逆に、負けるとウデマエメーターにヒビが入っていき、4つのヒビが入ると、ウデマエダウンして、下のランクに落ちます。4つのヒビが入るまでに、ウデマエメーターがある程度(40%)たまっていれば、ウデマエキープとなってランクは変動しません。

ガチマッチの勝率とウデマエアップの関係を調べてみました。というのも、たとえ勝率が5割であってもウデマエアップできるのではないかと感じたためです。勝率5割と言っても、勝ち、負け、勝ち、勝ち、勝ち、と瞬間的には大きく勝ち越すこともありますからね。それがどのくらいの確率なのかを調べようと思います。

負の二項分布

問題設定として、7回勝つとウデマエアップし、5回負けると4つのヒビが入るとします(実際、4回負けてもヒビは4つ入らないです。)。ウデマエアップのためには、5回負ける前に7回勝つ必要があります。勝率はpとします。

確率pで成功する独立なベルヌーイ試行が繰り返される時、r回失敗するまでに、k回成功する確率を表す確率分布があり、負の二項分布といいます。まさに今回の問題のためのような確率分布ですね!

 \displaystyle
f(k, r, p) = {}_{k+r-1}C_{k-1} p^{k-1} (1-p)^r p = {}_{k+r-1}C_{k-1} p^{k} (1-p)^r

「5回負ける前に7回勝つ」というのは、「7回勝つまでに、4回以下しか負けない確率」なので、

 \displaystyle
P(k=7, r \leq 4, p) = \sum_{r=0}^{4} {}_{7+r-1}C_6 p^{7} (1-p)^r

とかけます。勝率pによって確率が変わるので、これをみていきましょう。

勝率とウデマエアップの関係

ウデマエアップ確率Pを求める関数を定義。

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb

def get_probability(p, k=7):
    q = 1 - p
    sum = 0
    for r in range(4):
        sum += comb(k+r-1, k-1) * (q**r)
    return sum * (p**k)

勝率pを0から1までかえて、ウデマエアップ確率Pがどう変わるかをプロット。

ps = np.linspace(0, 1, 11)
probs = []
for p in ps:
    probs.append(get_probability(p))

plt.plot(ps, probs, 'o-')
plt.xlabel('Winning percentage, p')
plt.ylabel('Probability of Udemae-up, P')
plt.grid()
#plt.savefig('Udemae_up_1.png')
plt.show()

勝率p=50%だと、ウデマエアップできる確率は2割にも満たない。。。もっと高いかと思ったな。

次に、ウデマエアップを目指して4つヒビが入るまで挑戦するのを「1チャレンジ」として、5回チャレンジした時、10回チャレンジした時にウデマエアップできる確率を考えてみます。i回チャレンジして一度もウデマエアップできない確率を1から引けば良いので、

 \displaystyle
P_{challenge}(k=7, r \leq 4, p, i) = 1 - (1 - P(7, r \leq 4, p))^i

とかけます。これをプロットすると、

for i in [1, 5, 10]:
    probsChallenges = 1-(1-np.array(probs)) ** i
    label = f'{i} challenge' if i==1 else f'{i} challenges'
    plt.plot(ps, probsChallenges, 'o-', label=label)
plt.legend()
plt.xlabel('Winning percentage, p')
plt.ylabel('Probability of Udemae-up, P')
plt.grid()
#plt.savefig('Udemae_up_2.png')
plt.show()

勝率p=50%でも、5回チャレンジすればウデマエアップできる確率が6割を超えてくることがわかります。10回やれば、ほぼウデマエアップできますね。

なるほどー。

勝率とウデマエキープの関係

ついでなので、負の二項分布を使ってウデマエキープする確率(ウデマエダウンしない確率)も求めてみます。

ウデマエキープする確率を、「2回勝つまでに、4回以下しか負けない確率」とすると、

 \displaystyle
P(k=2, r \leq 4, p) = \sum_{r=0}^{4} {}_{2+r-1}C_1 p^{2} (1-p)^r

となります。プロットしてみると、

ps = np.linspace(0, 1, 11)
probs = []
for p in ps:
    probs.append(get_probability(p, k=2))

plt.plot(ps, probs, 'o-')
plt.xlabel('Winning percentage, p')
plt.ylabel('Probability of Udemae-keep, P')
plt.grid()
#plt.savefig('Udemae_up_3.png')
plt.show()

勝率p=50%の時は、8割以上の確率でウデマエキープできるはずってね。だからこそ落ちた時は、とても凹むんだけれども。(ウデマエメーターのスタートに依るので、ウデマエキープのために3回や4回勝たなくてはいけないこともあります。)

おわりに

何回かチャレンジすれば、勝率5割でもウデマエアップできる確率が大きくなるので、自分の感覚は合っていました。まぁ、勝率5割が難しいんですけど。ガチマッチは2時間でルールが変わっていきますが、2時間では1~1.5回くらいしかチャレンジできないので、容易に時間が溶けます。

ちなみに、スプラトゥーン3ではウデマエの仕組みも変わるようです(この記事の賞味期限もあとわずか)。

統計検定1級 過去問の出題内容一覧

注) 数学よわよわです。1級は1回落ちて、勉強中。

合格率の推移

受験データ|統計検定:Japan Statistical Society Certificate

1級「統計数理」

年度 申込者数 受験者数 合格者数 合格率
2019 1,285 878 202 23.0%
2018 881 592 124 20.9%
2017 526 322 79 24.5%
2016 499 266 70 26.3%
2015 415 244 26 10.7%
2014 484 288 38 13.19%
2013 402 227 32 14.10%
2012 228 158 25 15.82%

1級「統計応用」

年度 申込者数 受験者数 合格者数 合格率
2019 1,221 793 125 15.8%
2018 833 548 108 19.7%
2017 499 302 79 26.2%
2016 477 243 58 23.9%
2015 450 249 56 22.5%

1級「統計数理」

年度
概要
詳細 個人的なコメント
2019 1 確率母関数 期待値、分散、二項分布、 [3], [4]は数学
2 指数分布 期待値、再生性、 [4]の損失関数はどこからでてきたの?
3 順序統計量 十分統計量、条件付き同時分布、不偏推定量 [1]十分統計量、[5][6]の証明
4 検定 コーシー分布、検定のサイズ、検出力、尤度比、最強力検定、ネイマン・ピアソンの定理 検定。tan-1(x)はArctan(x)のことで、1/tan(x)のことではないよ。。。
5 ベイズ推定 ラプラス分布、期待値と分散、事後確率密度関数、Posterior mode、MLE [3]の場合分け
2018 1 カイ二乗分布 ガンマ関数、標準偏差、デルタ法、スターリングの公式 S2カイ二乗分布の関係は。
2 超幾何分布 場合の数と確率、超幾何分布の期待値と分散、デルタ法 [1]、[4]。[5]はムズすぎでは
3 二項分布 二項分布の期待値と分散、条件付き確率関数、条件付き期待値、条件付き分散、MLE、モーメント法
4 2変量正規分布 周辺分布、マルコフ性、条件付き期待値と分散、条件付き分散の公式 条件付き分散の公式
5 順序統計量 最小統計量と最大統計量 順序統計量のp.d.f.の導出は累積分布関数から。
2017 1 歪度と尖度 不偏推定量、標本平均の期待値と分散、標本分散、不偏分散 歪度と尖度の計算がエグい
2 最大統計量 順序統計量、最尤推定量、有効性 順序統計量の導出(累積分布から)を確認しておく
3 ポアソン分布の性質 二項分布との関係、モーメント母関数、再生性、標準正規分布との関係 ポアソン分布の総合問題
4 変数変換 相関係数、条件付き確率分布 変数変換=>ただ実直に計算して解くだけでなく、大局的にも考える。
5 変数変換 カイ二乗分布三角関数 (4)のヒントは使う必要ある?
2016 1 定量の性質 正規分布、モーメント母関数、最尤推定量、バイアス、不変性、平均二乗誤差MSE、フィッシャー情報量、クラメール・ラオの下限 時間
2 指数分布の最尤推定量とガンマ分布との関係 指数分布、分布関数、最尤推定量、不変性、ガンマ分布との関係 [4]ガンマ分布との関係の証明
3 線形モデルの母数の分散 線形モデル、最小二乗推定量、シュワルツの不等式、算術平均と調和平均の不等式 [2]線形モデル、[3]分散の比較(数学)
4 乱数の生成 モンテカルロ法正規分布、一様分布、分散 適宜、数値に
5 欠測データ MCAR、一元配置分散分析、F分布とt分布の関係 MACR
2015 1 k次モーメント、一致性 標本平均、不偏分散、k次モーメント、平均二乗誤差MSE、一致推定量、チェビシェフの不等式、 [3]k次モーメント、[4]一致性の証明
2 検定 P値、検出力、棄却域、ネイマン-ピアソンの定理、一様最強力検定 検定論
3 重回帰分析 正規方程式、最小二乗推定量相関係数、分散 計算量。。手を動かせ
4 分割表 多項分布、最尤推定値、尤度比検定 手を動かせ。
5 二標本 標本分散、相関係数、二変量正規分布、条件付き期待値 手を動かせ。
2014 1 順序統計量 条件付き確率、最大値
2 ガンマ分布 モーメント母関数、変数変換、行列式、指数分布、再生性、順序統計量 [3]と、そこから[4][5]への展開
3 検定 検定方式、分散が既知/未知、t分布、信頼区間 [1]基礎の理解、[2]計算
4 線形モデル 測定法、計画行列、正規方程式、最小二乗推定量、分散、F統計量、非心度、非心カイ二乗分布 問題は最後まで見てから解き始めよう
5 適合度検定 多項分布、二項分布、尤度関数、最尤推定値、適合度検定、適合カイ二乗統計量、尤度比統計量、自由度 適合度における自由度

1級「統計応用」

年度
概要
詳細 個人的なコメント
2019 1 生存時間解析 生存関数、ハザード関数、累積ハザード関数、平均余命関数、IFR、DFR、凸関数 [1]、[2]の計算
2 生産管理 X-R管理図、C管理図、中心線、管理限界線、郡内変動、3シグマルール、群間変動、維持管理、 どうやって勉強したらよいのか?
3 実験計画法 L8型直交表、主効果、平方和、誤差、F値、完全無作為化実験、1次因子、2次因子、分割実験、1次単位、 F値の計算
4 時系列分析、線形代数 AR(1)、定常性、自己共分散行列、自己相関行列、対称行列、逆行列行列式、2次形式、正定値、非負定値、自己回帰係数、誤差分散の区間推定 線形代数!
5 適合度検定 カイ二乗検定とその導出、最尤推定値、数値計算、反復法、EMアルゴリズム 適合度検定の導出、自由度。EMアルゴリズム
2018 1 指数分布 F、Mx(t)、再生性、ガンマ分布、一様分布との関係、幾何分布との関係、ポアソン分布との関係 指数分布の総合問題、連続確率分布と離散確率分布の関係
2 ワイブル分布 最頻値、ハザード関数、最尤法、ワイブル確率紙 (3)(4)工夫して解く
3 対数正規分布ベイズ 期待値、中央値、最頻値、MLE、事前分布、事後分布 計算、(3)ベイズ
4 実験計画法 直交表、主効果、2因子交互作用、交絡、主効果の推定、複合中心計画、回転可能性 勉強しないと
5 混合分布 正規分布標準偏差、二峰性 ゴリゴリ計算
2017 1 ガンマ分布 最尤法 [5]をちゃんと証明すること以外はそんなに難しくない?
2 ポアソン過程 指数分布との関係、MTTF(Mean time to failure)、信頼限界 (2)はポイント。(3) 信頼限界の定義をきちんと確認したい
3 条件付き分布 指数分布、条件付き期待値、尤度関数、最尤推定値、漸化式 (3)の尤度関数
4 ベータ分布、乱数生成 モンテカルロ法 (3)乱数生成方法を確認したい
5 場合の数 振り分け法、信頼区間 (2)一般的な数学力が問われる。(5)2級でもあるけど、数式に書き下すことが大事
2016 1 分散分析、推定量の分散 分散分析、最適性 [4]最適性とは
2 時系列解析 自己回帰過程、定常、期待値、自己共分散、自己回帰係数、ユール・ウォーカー方程式 時系列解析の基礎
3 工程能力指数 工程能力指数Cp、上側規格、下側規格、管理状態、カイ2乗分布 [5]計算を丁寧に
4 ポアソン分布 ポアソン分布、モーメント母関数、最頻値、最尤推定量、条件付き確率 [2]最頻値
5 信頼区間 t分布、信頼区間、2標本両側t検定 [3]信頼区間の重なり
2015 1 確率 部分分数分解 [3]数学
2 生存時間解析 ハザード関数、故障率関数、正規分布 [5]正規分布微分したときの性質
3 複合ポアソン過程 指数分布、ポアソン分布、モーメント母関数 [2]まずは問題の式を書いてみる。[3]複合ポアソン分布
4 角度確率変数 加法定理、モーメント法、 加法定理!!!! [6]の証明
5 分散分析 二元配置分散分析、分散分析表、交互作用、総平方和の分解、分散分析の誤差の分散 [4], [5]の理解
2014 1 検定 ポアソン分布、モーメント母関数、再生性、条件付き分布、条件付き検定、ポアソン性、検定方式 [3][4]
2 線形モデル 回帰係数の推定、分散、ぶんさん共分散行列、一般化分散、D-最適計画、予測分散 [3]予測分散
3 生存時間解析 指数分布、生存関数、ハザード関数、累積ハザード関数、カプラン・マイヤープロット、メジアン生存時間MST、最尤推定 生存時間解析の総合問題
4 時系列解析 確率過程、移動平均モデル、自己相関係数自己回帰モデル、最小二乗推定量、自己共分散、Yule-Walker方程式
5 適合度検定 独立性の検定、カイ二乗検定統計量、二項分布、検定、

メモ: 電卓の使い方

統計検定用にシャープのEL-N862という電卓をもっているので、そのメモ。

  • シャープのサイトのマニュアル
  • "基本計算のしかた"、"アンサーチェック(照合)のしかた"、"式の確認と訂正のしかた"、の3つを読めばOK
    • F4320Aは小数点位置。F(浮動)にする。
    • GT/アンサーチェックはGT(Ground Total)かアンサーチェックか。アンサーチェックで良いのでは。GT機能はM+使ったほうが間違えなさそう。
  • 平方根、べき乗計算(N*==)、逆数計算(N/=)、メモリー計算(A M+ B M+ R.CM)など使えると捗る。
  • 統計検定で使える (2級(ペーパー試験)での使用実績あり。)

Python Data Science Memo

General

  • Import
import os, sys
import re
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['figure.figsize'] = (16.0, 8.0)
plt.rcParams['figure.figsize'] = (16.0, 8.0)

import seaborn as sns
sns.set()
#sns.reset_orig()

pd.options.display.float_format = '{:,.2f}'.format

#import scipy as sp
#import statsmodels.api as sm
#import statsmodels.formula.api as smf

numpy

random

np.random.seed(0)

x = np.random.binomial(30, 0.5, 1000)
x = np.random.poisson(7, 1000)
x = np.random.normal(5, 10, 10000)
#x = np.random.lognormal(30, 0.4, 1000)

plt.hist(x)
#plt.hist(x, density=True)

#pd.Series(x).plot(kind='kde', style='k--')
#pd.Series(x).hist(density=True)

plt.grid(True)

Pandas

Basic

  • loc, iloc: df.iloc[10, df.columns.get_loc('name')]

groupby

Style

def highlight_max(s):
    is_max = s == s.max()
    return ['background-color: yellow' if v else '' for v in is_max]

df.style.apply(highlight_max, subset=['B', 'C', 'D'])

Matplotlib

subplots

# using the variable ax for single a Axes
fig, ax = plt.subplots()

# using the variable axs for multiple Axes
fig, axs = plt.subplots(2, 2)

twinx()

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density", zorder=2.3)
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature", zorder=2.2)
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity", zorder=2.1)

Plot function

def func(x):
    return x ** 2 + 2 * x + 1
x = np.linspace(-10, 10,101)
fig, ax = plt.subplots()
ax.plot(x, func(x))
ax.grid(True)
plt.show()

Misc

scikit-learn

  • Linear regression
from sklearn import linear_model
reg = linear_model.LinearRegression()
X = df.loc[:, ['A']].values
Y = df['B'].values
reg.fit(X, Y)
print('Regression coef:', reg.coef_)
print('Intercept:', reg.intercept_)

plt.scatter(X, Y)
plt.plot(X, reg.predict(X))
plt.grid(True)
  • train_test_split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)
  • Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
  • KMeans
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
X, _ = make_blobs(random_state=10)
kmeans = KMeans(init='random',n_clusters=3)
kmeans.fit(X)
y_pred = kmeans.predict(X)

merge_data = pd.concat([pd.DataFrame(X[:,0]), pd.DataFrame(X[:,1]), pd.DataFrame(y_pred)], axis=1)
merge_data.columns = ['feature1','feature2','cluster']

ax = None
colors = ['blue', 'red', 'green']
for i, data in merge_data.groupby('cluster'):
    ax = data.plot.scatter(x='feature1', y='feature2', color=colors[i], label=f'cluster{i}', ax=ax)
  • from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV holdout method, cross validation, grid search
  • confusion_matrix, precision_score, recall_score, f1_score, roc_curve, auc For classification
  • mean_squared_error, mean_absolute_error, median_absolute_error, r2_score For regression
  • from sklearn.ensemble import BaggingClassifier, AdaBoostRegressor Bagging, Boosting
  • Gradient Boosting, Random Forest
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor

boston = load_boston() # Housing
X_train, X_test, y_train, y_test = train_test_split(boston.data, boston.target, random_state=0)

models = {
  'RandomForest': RandomForestRegressor(random_state=0),
  'GradientBoost': GradientBoostingRegressor(random_state=0) 
}
scores = {}
for model_name, model in models.items():
    model.fit(X_train, y_train)
    scores[(model_name, 'train_score')] = model.score(X_train, y_train)
    scores[(model_name, 'test_score')] = model.score(X_test, y_test)

print(pd.Series(scores).unstack())

s = pd.Series(models['RandomForest'].feature_importances_,index=boston.feature_names)
s.sort_values(ascending=False).plot.bar()

統計のための数学

(随時更新)

Python Basic Memo

General

  • __import__('keyword').kwlist 予約語
  • dir(__builtins__) Builtin関数

file

glob.glob('*.gif')
['1.gif', 'card.gif']

function

Definition

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    for kw in keywords:
        print(kw, ":", keywords[kw])

Input

cheeseshop("Limburger", "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")

Output

-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch

datetime

datetime.timedelta(days=1).seconds # => 0
datetime.timedelta(days=1).total_seconds() # => 86400.0

json

logging

import logging
logging.warning('Watch out!')  # will print a message to the console
logging.info('I told you so')  # will not print anything
import logging
logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
logging.error('And non-ASCII stuff, too, like Øresund and Malmö')
import logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler("debug.log"),
        logging.StreamHandler()
    ]
)
import sys
sys.stdout = open('file', 'w')
print('test')

misc

Memo of M5StickC

M5StickC

Battery saving

Misc