ベイズ推定① モンテカルロ法
こんにちは、テックタヌキです。
普段はデータ分析のお仕事をしていて、学んだことのアウトプットをしています。
本記事では、ベイズ推定について学んだことをまとめます。
何か間違っているところがあれば指摘してもらえると喜びます。
はじめに
前回の記事では、EMアルゴリズムを使って尤度推定をしましたが、本記事ではベイズ推定を行います。
尤度推定は、未知のモデルパラメータ
ベイズ推定でも、同様に未知のパラメータに依存するモデル分布
ベイズ学習の枠組みでは、観測データDと確率モデル
また、尤度推定ではパラメータに対して点推定を行っていましたが、ベイズ推定では、事後分布をもとめるので、分布推定の問題になります。[1]
事後分布は、ベイズの定理から、以下のように求めることができます。[2]
1次元ガウス分布の場合
ものは試しということで、観測値が1次元ガウス分布に従う場合を例に考えてみます。単純のために、分散
また、事前分布を平均
ここで、
と分解できます。[3] 元の式の分母の積分の中身は分子と同じで、積分は
となります。[4]
よって、この式をグッと睨むと、
この事後分布における確率が最大となるパラメータを求めると(MAP推定といわれます)、事後分布は正規分布のためそれは平均
となります。[5] 尤度推定では
最尤推定の結果と比べてみましょう。最尤推定の場合、分散既知に対する正規分布の平均の最尤推定量は標本平均である
この理由は、
ベイズ推定の課題
上記のベイズ推定では、やや複雑ではありますが解析的に計算をすることができました。ベイズ推定の枠組みを再掲すると、以下のようになります。
改めて考えてみると、分母の積分が解析的に計算できますかどうかわかりません。また、数値計算の場合でも、積分の計算は重いです。[7]
種明かしをすると今回の場合には、事前分布には、共役事前分布という性質の良い分布を選んだために、解析的に計算をすることができました。
解析的に計算できない例として、事前分布として、以下の標準コーシー分布
を与えてみます。
事後分布の式に代入すると、
のようになります。
このようなとき、一般的には以下の2つの方法で解決します。ただし、事後分布を求めることは難しいので、パラメータに関する関数の値(たとえば平均や分散)を求めます。[8]
- ①サンプル平均で近似する
- ②事後分布にできるだけ近い分布を選んで計算する
サンプル平均で近似する場合
つまり、
分散も同様にして、
分散は分散公式から、以下のように推定できます。
シミュレーション
次の条件で、シミュレーションを行いました。
データ数:[5, 10, 50, 100, 200, 500, 1000, 2000]の8種類で生成
データ生成方法:未知の平均3、既知の分散が1の正規分布からデータを生成。
事前分布:標準コーシー分布
モンテカルロ平均に使うサンプルの数:1000
使用したコードは以下になります。
import numpy as np
import matplotlib.pyplot as plt
var_true = 1 # 既知の分散
mu_true = 3 # nuknownな平均
# 図の作成
fig, axs = plt.subplots(2, 4, figsize=(20, 10))
fig.suptitle('Monte Carlo Mean Simulation (1000 samples)', fontsize=16)
# シミュレーション
for iter, size in enumerate([5, 10, 50, 100, 200, 500, 1000, 2000]):
# 疑似データ
data = np.random.normal(loc=mu_true, scale=np.sqrt(var_true), size=size)
mean = np.mean(data)
mean_list = []
var_lsit = []
# モンテカルロ平均
sample = np.random.normal(loc=mean, scale=1/np.sqrt(size), size=1000) # 乱数を取得
for i in range(1000):
_sample = sample[:i] # 推移を見たいのでサンプルから部分列を取得
# モンテカルロ平均を求める式(累積和などを使えばもう少し効率がよさそうですが
# 本質ではないので愚直にやります)
montecalro_mean = np.mean(_sample/(1+_sample**2))/np.mean(1/(1+_sample**2))
montecalro_meansq = np.mean(_sample**2/(1+_sample**2))/np.mean(1/(1+_sample**2))
montecalro_var = montecalro_meansq - montecalro_mean**2
# 履歴を格納
mean_list.append(montecalro_mean)
var_lsit.append(montecalro_var)
# 可視化
row = iter // 4
col = iter % 4
axs[row, col].plot(range(1,1000 + 1), mean_list, color = 'black', label='estimate of mean of μ')
axs[row, col].fill_between(range(1,1000 + 1), np.array(mean_list)-3*np.sqrt(var_lsit), np.array(mean_list)+3*np.sqrt(var_lsit), alpha=0.3)
axs[row, col].axhline(y=mu_true, color='r', linestyle='--', label='μ_true')
axs[row, col].set_ylim(0, 5)
axs[row, col].set_title(f'Data size: {size}')
axs[row, col].set_xlabel('iter')
axs[row, col].set_ylabel('val')
axs[row, col].legend(loc='lower left')
次の図が、各データに対する未知パラメータ
図を見ると、いずれのデータ数でも平均、分散ともに収束していることがわかりますが、データ数が少ない場合には、真の平均3に対して、精度が悪い結果になりました。しかし、データ数が少ない場合にはその分、分散も大きくなっており、推定結果に自信がないことを表していることが考えられます。
ただし、データ数がある程度ある場合でも、取得したデータによって、真の値からずれる場合もあるようです。
まとめ
本記事では、分散既知の1次元ガウス分布の平均推定を行いました。
方法としては、共役事前分布を設定して解析的に事後分布を求めた場合と、共役事前分布ではない分布を事前分布にした場合にモンテカルロ平均によって、パラメータの期待値と分散を求めました。
次回の記事では、記事の中で言及していた変分ベイズの場合はどうなるかについて考えてみようと思います。
-
尤度推定では、真のパラメータがあるという立場をとります。いわゆる頻度論です。ギリシャ哲学的にいえば、神様が決めた真のパラメータで定まる確率モデル(イデア)からデータが生成(イデアのコピー)されていると考えるようです。オブジェクト指向のクラスとインスタンスの関係に似ているかもしれません。一方でベイズでは、真のパラメータなどないという立場をとり、パラメータも分布として現れます。 ↩︎
-
として扱う場合もあるようです。本記事ではp(D, \alpha, \theta)= p(D|\alpha, \theta) p(\theta|\alpha) は独立として扱います。 ↩︎D, \alpha -
について平方完成しただけです。 ↩︎\mu -
最後の等式変形は、ガウス積分の結果です。 ↩︎
-
分母の
はp(D, \sigma_0^2=1, \mu_0=0) を含まない定数のため、最大化の意味では無視できます。 ↩︎\mu -
最尤推定の場合は真のパラメータは一つという立場をとっているので、区間推定の結果はこのようなシンプルな解釈にはなりません。統計WEB
から引用すると、頻度論では以下のような直感的ではない解釈になります。「母集団から標本を取ってきて、その標本平均から母平均の95%信頼区間を求める、という作業を100回やったときに、95回はその区間の中に母平均が含まれる」ということを意味します。」 ↩︎ -
1次元の場合はあまり重くないかもしれませんが、多次元の場合に区分求積法で求めた場合、分割数が急激に増えるため計算量が非常に重くなります。 ↩︎
-
デルタ法などを活用すると、信用区間も求められますが、今回は割愛します。 ↩︎
-
本記事では尤度関数の分布に従う確率変数に対して期待値を取りましたが、事前分布に従う確率変数で期待値を取る場合もあるようです。どちらがいいかはわかりません。有識者の方は教えてください。 ↩︎
Discussion