import numpy as np
import math
import matplotlib.pyplot as plt
Basic Metropolis-Hastings
Base chain
Consider a Markov Chain that moves left/right with equal probability:
def base_chain(current_state):
= np.random.choice([-1,1])
move return current_state + move
= 0
current for t in range(20):
print(current, end=" -> ")
= base_chain(current) current
0 -> -1 -> -2 -> -1 -> 0 -> 1 -> 0 -> -1 -> 0 -> -1 -> -2 -> -3 -> -4 -> -5 -> -6 -> -5 -> -4 -> -5 -> -6 -> -7 ->
Target stationary distribution
We now wish to construct another chain with stationary distribution given by the following mixture
from scipy.stats import poisson
def mixture(n):
return 0.25 * poisson.pmf(n, mu=3.0, loc=0) \
+ 0.25 * poisson.pmf(n, mu=12.0, loc=0) \
+ 0.5 * poisson.pmf(n, mu=25, loc=0)
for n in range(0, 40)],
plt.plot([n for n in range(0, 40)], c='red', label='pi')
[mixture(n) plt.legend()
Metropolis-Hastings, acceptance probability
Since the base chain is symmetric (with transitions \(\psi(x,x\pm1)=1/2\)), the Metropolis scheme is defined as follows:
Given \(x_t\),
- Sample \(y_{t+1}\) according to \(\psi(x_t, \cdot)\),
- Either
- Accept the move (\(x_{t+1}=y_{t+1}\)) with probability \(a(x_t,y_t)=\min\{1, \pi(x)/\pi(y) \},\)
or
- Reject the move \((x_{t+1}=x_t\)) with probability \(1-a(x_t,y_{t+1})\).
- Accept the move (\(x_{t+1}=y_{t+1}\)) with probability \(a(x_t,y_t)=\min\{1, \pi(x)/\pi(y) \},\)
= 0
current = []
states_visited for t in range(100000):
= base_chain(current)
proposal = np.random.uniform()
U = mixture(proposal) / mixture(current)
a = proposal if U <= a else current
current
states_visited.append(current)
# Counting states visited by the metropolis chain
= np.unique(states_visited, return_counts=True)
states, counts /len(states_visited), label='States visited')
plt.bar(states, counts
# theoretical target distribution
for n in range(0, 40)],
plt.plot([n for n in range(0, 40)], c='red', label='pi')
[mixture(n) plt.legend()