【MCMC③】MCMCを用いて実際にサンプリングをしてみよう!

この記事では、MCMC(マルコフ連鎖モンテカルロ法)でサンプリングを行う手順と、Pythonを用いた実際の適用例をご紹介します!

目次

サンプリング手順について

MCMCを使用する際の基本的な手順は以下のようになります。

1. 問題の定式化

MCMCを使用する目的を明確にします。例えば、「確率分布からのサンプリング」や「ベイズ統計モデルの事後分布のパラメータ推定」などです。

2. MCMCアルゴリズムの選択

「メトロポリス・ヘイスティングス法」、「ギブスサンプリング」、「ハミルトニアン・モンテカルロ」など、適切なMCMCアルゴリズムを選択します。(→アルゴリズムの詳しい説明はこちら

パラメータ設定

アルゴリズムによって異なりますが、MCMCの主要なパラメータには、「初期値」、「バーンイン期間」、「ステップサイズ」 、「サンプル数」などがあります。

※バーンイン期間とは、アルゴリズムの初期段階で生成されるサンプルを、分析から除外する期間のことです。バーンイン期間が短すぎると、未収束のサンプルが分析に含まれるリスクがあります。一方で、長すぎると有用なサンプルを失うことになります。

3. サンプリングの実行

初期値を設定した後、選択したアルゴリズムに従って、目的の分布からサンプルを生成します。

4. 収束の確認

生成されたサンプルが目的の分布に収束しているかを評価します。

5. 結果の分析
  • バーンイン期間サンプルの除外:初期のサンプルを排除します。
  • 事後分布の分析(必要な場合):収束したサンプルを使用して、推定したいパラメータの事後分布を分析します。

実際にPythonで実装してみよう!

先ほどの5つのステップに則って、実際にサンプリングを行いたいと思います。

ここでは、簡単な統計モデル(ベイジアン線形回帰モデル)を取り上げ、MCMCを用いた事後分布のパラメータ推定を行うことを目標とします。

1. 問題の定式化

今回は、線形回帰モデルのパラメータ(傾きと切片)を推定することを目的とします。

モデル式は次のとおりです。

ϵ は誤差項で、正規分布に従うと仮定)

上式において、今回は真のパラメータを

と設定することにします。

はじめにライブラリのインポートと、仮想データの生成を行います。

import numpy as np 
import scipy.stats as stats 
import matplotlib.pyplot as plt 

#random.seedを設定 
np.random.seed(0) 
# 仮想データを作成 
x = np.linspace(0, 10, 100) y = 2.5 + 0.5 * x + np.random.normal(scale=1.0, size=100)

2. MCMCアルゴリズムの選択 および 3. サンプリングの実行

今回は、メトロポリス・ヘイスティングス法を選択します。

下記のコードでは、

  1. 現在のパラメータ値から新しい値を提案(正規分布を使用)
  2. 提案された値の受理確率を計算し、ランダムに受理/拒否を決定。
  3. このプロセスを5000回繰り返す

ということが行われています。

# メトロポリス・ヘイスティングス法
def metropolis_hastings(lr, iterations, x, y):
beta_0 = 0
beta_1 = 0
sigma = 1
samples = []
for i in range(iterations):
beta_0_proposal = np.random.normal(beta_0, lr)
beta_1_proposal = np.random.normal(beta_1, lr)
sigma_proposal = np.random.normal(sigma, lr)


likelihood_current = np.sum(stats.norm.logpdf(y, beta_0 + beta_1 * x, sigma))
likelihood_proposal = np.sum(stats.norm.logpdf(y, beta_0_proposal + beta_1_proposal * x, sigma_proposal))


prior_current = stats.norm.logpdf(beta_0, 0, 10) + stats.norm.logpdf(beta_1, 0, 10) + stats.halfnorm.logpdf(sigma, 0, 1)
prior_proposal = stats.norm.logpdf(beta_0_proposal, 0, 10) + stats.norm.logpdf(beta_1_proposal, 0, 10) + stats.halfnorm.logpdf(sigma_proposal, 0, 1)


#受理確率
p_accept = np.exp(likelihood_proposal + prior_proposal - likelihood_current - prior_current)


if np.random.rand() < p_accept:
beta_0, beta_1, sigma = beta_0_proposal, beta_1_proposal, sigma_proposal


samples.append([beta_0, beta_1, sigma])


return np.array(samples)


# MCMCを実行
samples = metropolis_hastings(0.05, 5000, x, y)

4. 収束の確認

本来なら、次に収束判定を行いますが、ここではコードが長く複雑なものになってしまうため、省略します。

5. 結果の分析

# バーンイン期間を取り除く
burn_in = 500
post_burn_in_samples = samples[burn_in:]

バーンイン期間の除外後、残りのサンプルを使用して、β0 と β1 の事後分布を分析します。

plt.figure(figsize=(12, 6))

# beta_0の事後分布
plt.subplot(311)
plt.hist(post_burn_in_samples[:, 0], bins=30, density=True)
plt.title('Posterior of $\\beta_0$ After Burn-in')

# beta_1の事後分布
plt.subplot(312)
plt.hist(post_burn_in_samples[:, 1], bins=30, density=True)
plt.title('Posterior of $\\beta_1$ After Burn-in')

#事後分布の平均を求める
mean_beta_0 = np.mean(post_burn_in_samples[:, 0])
mean_beta_1 = np.mean(post_burn_in_samples[:, 1])
print(mean_beta_0, mean_beta_1)


 

MCMCでサンプリングした事後分布の平均は、

print(mean_beta_0, mean_beta_1)

にて出力しています。その結果は、

となりました。

はじめに、真のパラメータは、

と設定しましたので、サンプリングにより、真のパラメータに比較的近いものが得られたのではないでしょうか。

以上、Pythonを用いてMCMCでサンプリングを行う方法をご紹介しました。今回は、アルゴリズムをより深く理解するために、ライブラリは用いずに関数を定義しましたが、ライブラリPyMC3を使うと簡単に実装できます。

CTA
  • URLをコピーしました!
  • URLをコピーしました!
この記事を書いた人
目次