ベルヌーイ分布
0 = 黒、1 = 赤として赤の出る確率 \(p\) を調整できるベルヌーイ試行のシミュレーション。+1 ボタンを押すと試行を 1 回行う。
\(b\) | 0 | 1 |
---|---|---|
確率 \(P(b)\) | ||
\(x_b\)期待値 \(nP(b)\) | ||
観測回数 \(N_b\) |
定義と性質
結果が {0, 1}、{true, false}、{OK, NG} といった 2 値しかとりえない独立した事象の試みをベルヌーイ試行 (bernoulli trial) と呼ぶ。これらの結果は統計で扱う便宜上 \(b \in \{0,1\}\) に置き換えて考える。
ベルヌーイ試行において確率 \(0 \leq p \leq 1\) で 1 が出る場合 \(\sum_{b=0}^1 P(b) = 1\) より: \[ \begin{align*} P(b) & = \left\{\begin{array}{ll} p & (b = 0) \\ 1 - p & (b = 1) \end{array} \right. \\ & = p^b(1-p)^{1-b} \end{align*} \]
この \(p\) をパラメータとした \(b\) の確率分布 \(P(b; p)\) をベルヌーイ分布 (bernoulli distribution) と呼ぶ。ベルヌーイ試行を \(n\) 回行ったときの 1 の観測回数の分布は二項分布で表される。また 2 値ではなく \(k\) 値に一般化した分布はカテゴリカル分布となる。
アルゴリズム
ベルヌーイ試行関数
呼び出しごとに確率 \(p\) で true
を返すベルヌーイ試行関数を考える。この場合、一般的なプログラミング言語で用意されている \([0, 1)\) の範囲を取る一様疑似乱数が \(p\) より小さいかで判定すれば良い。
def trial(p:Double):Boolean = math.random() < p
なお関数に与えられた p
が \(0 \leq p \lt 1\) の条件を満たしていない場合の対処は省略している。実行結果は以下の通り。
scala> trial(0.6)
res1: Boolean = false
scala> trial(0.6)
res0: Boolean = true
scala> trial(0.6)
res1: Boolean = true
確率関数
この程度の条件であれば実装上はべき乗を使用するより if
で分岐したほうが計算量が少なくコードの可視性も損ねない。
def p(p:Double)(b:Boolean):Double = if(b) p else (1 - p)
上記は Scala のカリー化を使用している。引数 p=0.6
を指定した時点でパラメータ \(p=0.6\) を束縛した関数 (つまり確率分布が特徴づけされた確率関数) が得られるので確率分布を扱う上では便利かもしれない。
scala> val p6 = p(0.6) _
p6: Boolean => Double = $$Lambda$1087/1558931350@2aa176de
scala> p6(true)
res0: Double = 0.6
scala> p6(false)
res1: Double = 0.4
scala> p(0.75)(true)
res2: Double = 0.75