Mímisbrunnr知恵の泉

← シミュレーション 一覧

🎓 レベル:発展 | 重要度:A(必須)

📎 前提:マルコフ連鎖と定常分布 | 関連:ギブスサンプリング | ベイズ:メトロポリスヘイスティングス

要点(BLUF)

1. アルゴリズム

サンプルしたい目的分布 π(x)\pi(x)規格化されていなくてよい)に対し:

  1. 現在地 xx から、提案分布 q(xx)q(x'|x) で候補 xx' を生成
  2. 受理確率を計算:
α(x,x)=min ⁣(1, π(x)q(xx)π(x)q(xx))\alpha(x, x') = \min\!\left(1,\ \frac{\pi(x')\,q(x \mid x')}{\pi(x)\,q(x' \mid x)}\right)
  1. 確率 α\alphaxx' へ移動、確率 1α1-\alphaxx に留まる
  2. 現在地を記録して1へ

提案が対称q(xx)=q(xx)q(x'|x)=q(x|x')、ランダムウォークなど)なら qq が消えて α=min(1,π(x)/π(x))\alpha = \min(1, \pi(x')/\pi(x))メトロポリス法)。「目的密度が高い方へは必ず動き、低い方へは確率的に動く」だけです。

flowchart TD
    A["現在地 x から候補 x' を提案 q(x'|x)"] --> B["受理確率 α を計算"]
    B --> C{"乱数 u < α ?"}
    C -->|"はい"| D["x' へ移動"]
    C -->|"いいえ"| E["x に留まる"]
    D --> F["現在地を記録"]
    E --> F
    F --> A

2. なぜ π が定常分布になるか(詳細釣り合い)

MH の遷移核 K(xx)K(x \to x') は**詳細釣り合い(detailed balance)**を満たします:

π(x)K(xx)=π(x)K(xx)\pi(x)\,K(x \to x') = \pi(x')\,K(x' \to x)

xx から xx' への確率の流れ」と「逆向きの流れ」が各ペアで釣り合う、という条件。これを満たせば両辺を xx で和(積分)して

xπ(x)K(xx)=π(x)xK(xx)=π(x)\sum_x \pi(x)\,K(x \to x') = \pi(x')\sum_x K(x'\to x) = \pi(x')

すなわち πK=π\pi K = \piπ\pi が定常分布になります(マルコフ連鎖と定常分布)。受理確率 α\alpha の比の形は、まさにこの詳細釣り合いを成立させるよう逆算されたものです。実際 π(x)q(xx)α(x,x)=min(π(x)q(xx),π(x)q(xx))\pi(x)q(x'|x)\alpha(x,x') = \min(\pi(x)q(x'|x), \pi(x')q(x|x'))xxx \leftrightarrow x' で対称——だから流れが釣り合います。

肝心なのは、α\alpha に現れるのはπ(x)/π(x)\pi(x')/\pi(x) だけなので、π\pi の規格化定数(積分して1にする定数)が約分されて要らないこと。ベイズの事後分布のように規格化定数が計算困難な分布でもサンプルできる——これが MCMC が推論に不可欠な理由です(ベイズ)。

3. 実装:標準正規をランダムウォークMHで

目的 π(x)ex2/2\pi(x) \propto e^{-x^2/2}(標準正規、規格化定数は無視)、提案は対称な x=x+N(0,step2)x' = x + \mathcal{N}(0, \text{step}^2)

import numpy as np

# 乱数シードを固定
rng = np.random.default_rng(41)

def target_logpdf(x):
    return -0.5 * x**2              # 標準正規の対数密度(規格化定数なし)

n = 200_000
step = 2.0                          # 提案の歩幅
x = 0.0
samples = np.empty(n)
accept = 0
for i in range(n):
    x_prop = x + rng.normal(0, step)
    log_alpha = target_logpdf(x_prop) - target_logpdf(x)   # log(π(x')/π(x))
    if np.log(rng.random()) < log_alpha:                   # 受理判定
        x = x_prop; accept += 1
    samples[i] = x

burn = 2000                         # バーンイン除去
s = samples[burn:]
print(f"受理率 = {accept/n:.3f}")
print(f"標本平均 = {s.mean():.4f}  (目標 0)")
print(f"標本標準偏差 = {s.std():.4f}  (目標 1)")
print(f"標本 P(X>1.96) = {(s>1.96).mean():.4f}  (目標 0.025)")

出力:

受理率 = 0.500
標本平均 = -0.0016  (目標 0)
標本標準偏差 = 1.0006  (目標 1)
標本 P(X>1.96) = 0.0250  (目標 0.025)

出力の意味:受理率 0.500 で、規格化定数を一切使わずに標準正規からサンプルできています。標本平均 0.002-0.002、標準偏差 1.0011.001、上側裾確率 P(X>1.96)=0.025P(X>1.96)=0.025(正規の理論値そのもの)。連鎖を歩いた軌跡の頻度が、見事に目標分布を再現しました。受理確率の比 ex2/2/ex2/2e^{-x'^2/2}/e^{-x^2/2} だけで動いている点が MH の本質です。

4. 提案の歩幅とチューニング

提案の歩幅 step は効率を大きく左右します。

歩幅は試行錯誤か適応的 MCMC で調整します。受理率・自己相関・有効標本サイズ(収束診断と実装の注意)を見ながらチューニングするのが実務です。

数式の直観的意味

MH は「目的分布の地形を、確率的に登り降りする探索」です。密度が高い(標高が高い)方へは必ず登り、低い方へも比の確率で降りる——だから山頂(モード)に居座らず、谷(裾)も適切な頻度で訪れる。受理確率の比 π(x)/π(x)\pi(x')/\pi(x) が「降りる勇気」を制御し、これが正確に詳細釣り合いを満たすよう設計されているので、長時間の滞在頻度が π\pi に一致する。規格化定数が要らないのは「比を取れば全体の定数倍が消える」から——「絶対的な確率」ではなく「相対的な確率の比」だけで歩ける、というのが MCMC が高次元・複雑分布で勝つ核心です。

⚠️ よくある誤解・落とし穴

対応シミュレーション参照

本文のランダムウォーク MH(標準正規目標・default_rng(41)、受理率0.50)。推論応用はベイズへ。

関連ノート