MCMCとは
ベイズ推定などで、データ を与えたうえでの確率分布 (パラメータ の事後分布)を知りたい場合があります。このような場合、確率変数の状態遷移を記述する マルコフ連鎖 と乱数を用いる モンテカルロ法 を組み合わせた マルコフ連鎖モンテカルロ (MCMC) が有効とされます。MCMCは、 を直接求めるのではなく、適当な確率分布から繰り返しランダムサンプリングを行うことでマルコフ連鎖を構成し、その収束をもって目的の事後分布を再現する 方法であり、複数のアルゴリズムが提案されています。
マルコフ連鎖
定義
時間ステップ に対して決まる確率変数列 に対して、その観測値を とします。このとき、
をみたす系列 は マルコフ連鎖 とよばれます。すなわち、ある時刻での状態は、その直前の状態にのみ依存して決定されることを指します。
定常分布
は 遷移確率(遷移核) とよばれます。いま、状態遷移 を考えるとき、
であるならば分布 は遷移の前後で変化せず、これを 定常分布 といいます。
詳細つり合い条件
定常分布はどんなマルコフ連鎖にも存在するわけではありません。MCMCのキモは、定常分布をもつようなマルコフ連鎖を生成して、収束にもっていくことであるといえます。そのような理由から、マルコフ連鎖が定常分布をもつための条件について考える必要があります。実際にそのような条件は存在して、これを 詳細つり合い条件 といいます:
メトロポリス法
概要
データ を与えたうえでのパラメータ の事後分布 からサンプリングを行うのがMCMCの目的でした。ベイズの定理を用いれば、
ですが、いま (分子)は既知であるとしても、パラメータ空間をなめながらの積分(分母、周辺尤度)が計算できないことを想定します。このような場合には、適当に決めた分布(提案分布)から繰り返しランダムサンプリングを行い、マルコフ連鎖を構成してその定常分布として事後分布 を定めます。そのようなアルゴリズムの代表例が メトロポリス法 です。
アルゴリズム
状態遷移 について、定常分布 の確率関数に比例するような を考えましょう。このとき、詳細つり合い条件が成り立っているとすれば、
のように表すことができます。しかしながら、 については容易に知ることはできないため、上式をそのまま利用することは困難です。そこで、遷移核として提案分布 の確率関数 を用います(次の候補 を から拾います)。メトロポリス法においては、さらに
の条件を課し、提案分布は "左右対称" であるとします(例えば、一様分布 など)。
遷移核を提案分布から求めることによって、詳細つり合い条件の等号は破れてしまいます。そこで、採択率:
を都度計算し、その結果によって処理を分岐します。具体的には、
- のとき:
- 確率 で を採択()し、 で棄却()する。
- のとき:
- 確率 で確定的に を採択()する。
というアルゴリズムで列 を決定します。このような列は、十分な試行回数の下で目標分布 へ到達します。
Pythonによるメトロポリス法
モデル
連続一様分布 を提案分布とし、2次元正規分布 からサンプリングをしてみたいと思います[1]。
次点の候補 は、 なる一様乱数を用いて、
と定めます。採択率は、
とします。
コーディング
参考コード
列 は、変数 x1
x2
を保持しながら再代入を繰り返すことで再現します。また、「確率 で を採択する」の部分は、 random.uniform(0,1)
からランダムに生成した値 p
が alpha
より大きいか小さいかで判断しています。
また、メトロポリス法の欠点として、提案された候補の採択率が低い( が採択されにくい) ため、特に列の最初では重複を多く含んでしまうことが挙げられます(Burn-in)。この影響を避けるため、5,000回の試行のうち最初の500サンプルは捨てています。
import random
import numpy as np
import matplotlib.pyplot as plt
# destination distribution
def f(x1, x2):
return np.exp(-0.5 * (x1**2 + x2**2))
# proposal distribution
def q():
return random.uniform(-1, 1)
# samples
samples = []
# initial value
x1 = 0
x2 = 0
count = 0
# iterations
for i in range(5000):
# calculate next value
x1_prime = x1 + q()
x2_prime = x2 + q()
# calculate acceptance probability
alpha = min(1, f(x1_prime, x2_prime) / f(x1, x2))
# accept or reject
if (alpha <= 1):
p = random.uniform(0, 1)
if (p <= alpha):
x1 = x1_prime
x2 = x2_prime
else:
x1 = x1_prime
x2 = x2_prime
# update count
count += 1
# append samples
if (count > 500):
samples.append([x1, x2])
# scatter plot
plt.title("Metropolis algorithm")
plt.scatter(list(map(lambda x: x[0], samples)), list(map(lambda x: x[1], samples)), alpha = 0.5)
plt.xlabel('x1')
plt.ylabel('x2')
plt.legend()
plt.grid(True)
plt.show()
平均 を中心に点の密度が高くなっており、2次元正規分布 を再現していそうです。
ギブズサンプリング
概要
ギブズサンプリング は多次元の分布を推定したい場合に有効です。この方法では、サンプリングしたい事後分布 に対し、条件付き分布:
を提案分布として次点の候補 を決定します。
アルゴリズム
に対し、次の候補点 を以下のようにして決めます。
- を からサンプリング
- を からサンプリング
- を からサンプリング
- 以下、 次元まで繰り返し
このアルゴリズムが成立するためには、条件付き分布が単純な形で書き表される必要があります[2]。
Pythonによるギブズサンプリング
モデル
2次元正規分布 からサンプリングをします。そのために、同時確率関数:
をもちいて条件付き分布 を求めます。
対称性から でもあります。これらを用いてサンプリングを実行します。
コーディング
この例では条件付き分布が正規分布 であるので、 を正規乱数 np.random.standard_normal()
としています。また、最初の500サンプルはBurn-inとして破棄しています。
import numpy as np
import matplotlib.pyplot as plt
# samples
samples = []
# initial value
x1 = 0
x2 = 0
count = 0
# iterations
for i in range(5000):
# calculate next value
x1_prime = np.random.standard_normal()
x2_prime = np.random.standard_normal()
x1 = x1_prime
x2 = x2_prime
# update count
count += 1
# append sample every 10 counts
if (count > 500):
samples.append([x1, x2])
# scatter plot
plt.title("Gibss sampling")
plt.scatter(list(map(lambda x: x[0], samples)), list(map(lambda x: x[1], samples)), alpha = 0.5)
plt.xlabel('x1')
plt.ylabel('x2')
plt.legend()
plt.grid(True)
plt.show()
こちらも2次元正規分布 を再現していそうです。
参考
【MCMC法シリーズその1】MCMC法の概要とメトロポリス法 | note
メトロポリス・ヘイスティング法(マルコフ連鎖モンテカルロ法における手法の一つ)を実装を交えて理解する | Qiita
モンテカルロ法における詳細釣り合い条件と遷移確率の決め方について | Qiita