πŸŽ‰ 75% of content is free forever β€” Unlock Premium from $10/mo β†’
CW
Search courses…
πŸ’Ό Servicesℹ️ Aboutβœ‰οΈ ContactView Pricing Plansfrom $10

MCMC Diagnostics and Convergence

Advanced Statistical MethodsBayesian Methods🟒 Free Lesson

Advertisement

MCMC Diagnostics and Convergence

Advanced Statistical Methods

Knowing When Your MCMC Has Converged

MCMC diagnostics verify that Markov chain samples have converged to the target posterior distribution, preventing invalid Bayesian inference. Tools like R-hat, effective sample size, and trace plots are essential safeguards.

  • Bayesian modeling β€” Validate that posterior samples accurately represent the target distribution
  • Pharmacokinetics β€” Ensure reliable parameter estimates from complex hierarchical models
  • Computational biology β€” Confirm MCMC chains explore the full posterior in high-dimensional problems

Diagnostics are the quality control of Bayesian computation β€” never trust a chain you haven't checked.


Markov Chain Monte Carlo (MCMC) methods generate samples from posterior distributions that cannot be evaluated analytically. Proper diagnostics are essential to ensure the samples are valid representations of the target distribution.


MCMC Fundamentals


Metropolis-Hastings Algorithm


Gibbs Sampling


Convergence Diagnostics

R-hat (Gelman-Rubin Statistic)

More precisely:

Effective Sample Size (ESS)

ESS measures the number of independent samples equivalent to the correlated MCMC output. High autocorrelation reduces ESS. A minimum of ESS is recommended for reliable posterior summaries.

Autocorrelation


Thinning and Burn-in


Geweke Diagnostic


Brooks-Gelman-Rubin Multivariate Diagnostic

The multivariate (Vehtari et al., 2021) monitors all parameters simultaneously and is more sensitive to divergence in high-dimensional posteriors. is the recommended threshold.


Divergent Transitions (HMC/NUTS)


Python Implementation

import numpy as np
import pymc as pm
import arviz as az
import matplotlib.pyplot as plt

np.random.seed(42)

# --- Simple model for demonstration ---
n_obs = 200
X = np.random.randn(n_obs)
true_beta = np.array([1.5, -2.0])
y = true_beta[0] + true_beta[1] * X + np.random.randn(n_obs) * 0.5

with pm.Model() as demo_model:
    beta = pm.Normal('beta', mu=0, sigma=10, shape=2)
    sigma = pm.HalfNormal('sigma', sigma=2)
    mu = beta[0] + beta[1] * X
    y_obs = pm.Normal('y_obs', mu=mu, sigma=sigma, observed=y)
    
    # Run MCMC with diagnostics
    trace = pm.sample(2000, tune=1000, chains=4, return_inferencedata=True,
                      random_seed=42)

# --- R-hat ---
print("=== R-hat ===")
print(az.rhat(trace, var_names=['beta', 'sigma']))

# --- Effective Sample Size ---
print("\n=== Effective Sample Size ===")
print(az.ess(trace, var_names=['beta', 'sigma']))

# --- Autocorrelation ---
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
for i, ax in enumerate(axes.flatten()):
    if i < 2:
        az.plot_autocorr(trace, var_names=['beta'], combined=True, ax=ax)
    elif i == 2:
        az.plot_autocorr(trace, var_names=['sigma'], combined=True, ax=ax)
    else:
        az.plot_posterior(trace, var_names=['beta'], ax=ax)
plt.tight_layout()
plt.savefig('mcmc_autocorr.png', dpi=150)
plt.show()

# --- Trace plots ---
az.plot_trace(trace, var_names=['beta', 'sigma'], compact=True)
plt.tight_layout()
plt.savefig('mcmc_trace.png', dpi=150)
plt.show()

# --- Rank plots (modern diagnostic) ---
az.plot_rank(trace, var_names=['beta'])
plt.tight_layout()
plt.savefig('mcmc_rank.png', dpi=150)
plt.show()

# --- Geweke diagnostic ---
# Manual implementation for demonstration
from scipy import stats as sp_stats

def geweke_diagnostic(chain, first=0.1, last=0.5):
    n = len(chain)
    first_end = int(n * first)
    last_start = int(n * (1 - last))
    mean_first = np.mean(chain[:first_end])
    mean_last = np.mean(chain[last_start:])
    var_first = np.var(chain[:first_end]) / first_end
    var_last = np.var(chain[last_start:]) / (n - last_start)
    z = (mean_first - mean_last) / np.sqrt(var_first + var_last)
    p_value = 2 * (1 - sp_stats.norm.cdf(abs(z)))
    return z, p_value

print("\n=== Geweke Diagnostic ===")
for name in ['beta', 'sigma']:
    samples = trace.posterior[name].values.flatten()
    z, p = geweke_diagnostic(samples)
    print(f"{name}: z={z:.3f}, p={p:.3f} {'βœ“' if abs(z) < 2 else 'βœ—'}")

Related Topics


Key Takeaways

Need Expert Statistics Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement