2項分布による簡単なベイズ分析
グリッド法
2項分布のようにパラメータが1個で値域が有界な場合は、ベイズ統計分析(ベイズ統計分析の基礎的説明のウェブサイトも用意している)における事後分布はグリッド法で簡単に求めることができる。
2項分布の場合、N回の試行において当該の事象が試行生起したときの尤度関数は
で与えられる。したがって、事前分布として一様分布をとれば、事後分布は次式で与えられる。
尤度関数を次のスクリプト
def LF(p, N, k):
return (p ** k) * ((1.0 - p)
** (N - k))
で与え、グリッド法によって事後確率を得るためのクラス型PostPを以下のように宣言する。
n_grid = 100000
class PostP:
def __init__(self, N, k):
self.N = N
self.k = k
self.value = []
sum
= 0.0
for
i in range(0, n_grid + 1):
v = LF(i / n_grid, self.N, self.k)
self.value.append(v)
sum += v
for
i in range(0, n_grid + 1):
self.value[i] =
self.value[i] / sum
def d_p(self, i):
return self.value[i]
クラスPostPのメソッドd_pによって i 番目のグリッドの値が得られる。グリッドは、0から1までの区間 [0, 1] がn_grid = 100000 個に区切られているものである。0番目のグリッドの点が確率p の値0に、n_grid = 100000 番目のグリッドの点が確率p の値1に対応している。このクラス型を用いた例を以下に示す。このプログラム例は、実行すると分析結果が図1のように表示される。
図1
Nが総試行数、kが当該事象の生起数であり、成功確率 p のMAP(Maximum A Posteriori;事後分布のモード)推定値と95%確信区間(95% CI)がグラフの上部に表示されている。Nとkの値は、プログラムを実行すると図2のように聞いてくるので、計算したい値を設定すればよい。
図2
kの値を設定してEnterキーを押すと、図3のように計算結果が書き出され、図1のグラフが表示される。
図3
図1のフォームの右上のX印をクリックして閉じると、次のNの値の設定が求められる(図4)。
図4
次の計算用のNとkの値を設定すれば、それに対応した計算が行われ、グラフが表示される。Nに負の値を設定すると、プログラムの実行終了となる。
プログラムのリストは以下に示すとおりである。なお、図1、図4では95%確信区間(95% CI)が求められているが、95%最高密度区間(95% HDR;Highest Density Region)(図5)を求めるプログラムも作成した。これは、このウェブサイトの後半に載せてある。これらのプログラムのスクリプトファイルは圧縮ファイルBinBysnPrg.zipにまとめた。
import
matplotlib.pyplot as plt
import numpy as np
def LF(p, N, k):
return (p ** k) * ((1.0 - p)
** (N - k))
n_grid = 100000
class PostP:
def __init__(self, N, k):
self.N = N
self.k = k
self.value = []
sum
= 0.0
for
i in range(0, n_grid + 1):
v = LF(i / n_grid, self.N, self.k)
self.value.append(v)
sum += v
for
i in range(0, n_grid + 1):
self.value[i] = self.value[i] / sum
def d_p(self, i):
return self.value[i]
while (True):
N = int(input('N = '))
if (N < 1):
break
k = int(input('k = '))
postP = PostP(N, k)
alpha = 0.05
L_p = -1
sum = 0.0
while (sum < alpha /
2.0):
L_p
+= 1
sum
+= postP.d_p(L_p)
#print('sum(L) = ', sum,
' L_p = ', L_p)
L_p = L_p / n_grid
R_p = n_grid + 1
sum = 0.0
while (sum < alpha /
2.0):
R_p
-= 1
sum
+= postP.d_p(R_p)
#print('sum(R) = ', sum,
' R_p = ', R_p)
R_p = R_p / n_grid
print('\nN = ', N, ' k = ', k)
print('MAP = ', k / N)
print('95% CI = [{0:.3f},
{1:.3f}]'.format(L_p, R_p))
plt.title(('MAP =
{0:.3f} for N = {1}, k =
{2}\n'.format(k / N, N, k)) +
('95% CI = [{0:.3f}, {1:.3f}]'.format(L_p, R_p)))
x = []
y = []
for i in range(0, n_grid +
1, n_grid // 1000):
x.append(i / n_grid)
y.append(postP.d_p(i))
plt.plot(x, y, 'b-')
plt.show()
95%最高密度区間を求めるプログラム
以下のプログラムでは、図5に示すように95%最高密度区間(95% HDR)が求められる。
図5
図5のグラフを表示するスクリプトは以下の通りである。
import
matplotlib.pyplot as plt
import numpy as np
def LF(p, N, k):
return (p ** k) * ((1.0 - p)
** (N - k))
n_grid = 100000
class PostP:
def __init__(self, N, k):
self.N = N
self.k = k
self.value = []
sum
= 0.0
for
i in range(0, n_grid + 1):
v = LF(i / n_grid, self.N, self.k)
self.value.append(v)
sum += v
for
i in range(0, n_grid + 1):
self.value[i] = self.value[i] / sum
def d_p(self, i):
return self.value[i]
while (True):
N = int(input('N = '))
if (N < 1):
break
k = int(input('k = '))
postP = PostP(N, k)
alpha = 0.05
temp_L = 0
temp_R = n_grid
L_p = temp_L
while True:
if
L_p == 0:
SumP = postP.d_p(L_p)
R_p = L_p
else:
SumP -= postP.d_p(L_p - 1)
while (SumP < 1 - alpha):
R_p += 1
if R_p > n_grid:
break
SumP += postP.d_p(R_p)
if R_p
> n_grid:
break
if
(temp_R - temp_L) > (R_p - L_p):
temp_L = L_p
temp_R = R_p
L_p
+= 1
if
L_p > n_grid:
break
L_p = temp_L / n_grid
R_p = temp_R / n_grid
print('\nN = ', N, ' k = ', k)
print('MAP = ', k / N)
print('95% HDR = [{0:.3f},
{1:.3f}]'.format(L_p, R_p))
plt.title(('MAP =
{0:.3f} for N = {1}, k =
{2}\n'.format(k / N, N, k)) +
('95% HDR = [{0:.3f}, {1:.3f}]'.format(L_p, R_p)))
x = []
y = []
for i in range(0, n_grid +
1, n_grid // 1000):
x.append(i / n_grid)
y.append(postP.d_p(i))
plt.plot(x, y, 'b-')
plt.show()