Example 5.6#

MH sampler for a Gaussian with an independent proposal.

import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(42)

def p(x, mu, sigma): # just for plotting purposes
    return 1/np.sqrt(2*np.pi * sigma**2) * np.exp(-(x-mu)**2/(2*sigma**2))

def logp(x, mu, sigma):
    return -(x-mu)**2/(2*sigma**2) - np.log(np.sqrt(2*np.pi * sigma**2))

def logq(x, mu_q, sigma_q):
    return -(x-mu_q)**2/(2*sigma_q**2) - np.log(np.sqrt(2*np.pi * sigma_q**2))

def log_r(x, x_p, mu, sigma, mu_q, sigma_q):
    return logp(x_p, mu, sigma) - logp(x, mu, sigma) - logq(x_p, mu_q, sigma_q) + logq(x, mu_q, sigma_q)

fig = plt.figure(figsize=(10, 5))
N = 100000

mu = 2
sigma = 1
mu_q = 2
sigma_q = 2
x = np.zeros(N)
x[0] = 10

acc = 0

for n in range(1, N):
    x_s = rng.normal(mu_q, sigma_q, 1)
    u = rng.uniform(0, 1, 1)

    if np.log(u) < log_r(x[n-1], x_s, mu, sigma, mu_q, sigma_q):
        x[n] = x_s
        acc += 1
    else:
        x[n] = x[n-1]

burnin = 100
plt.clf()
plt.subplot(1,2,1)
plt.hist(x[burnin:], bins=100, density=True, color=[0.8, 0, 0], alpha=0.5)
plt.plot(np.linspace(-4, 8, 100), p(np.linspace(-4, 8, 100), mu, sigma), label='p', color='k')
plt.subplot(1,2,2)
plt.plot(x[burnin:n], '.--', color=[0.8, 0, 0])
plt.title('Acceptance rate: ' + str(acc/n))
plt.show(block=False)
plt.pause(0.1)
<ipython-input-1-b2df3b408ba2>:35: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
  x[n] = x_s
../_images/6da9c6453f67ab96bb13ee627191b811908ba3c7659eec42bf6e0f0eebf31f00.png

Play with the above code changing burnin and initial points as well as proposal variance.