GitHub profile

Step 4 - Convergence Diagnostics

Notation

Before trusting any of the posterior draws from Step 3, check that the chains actually converged and mixed well:

step 1 - summary table (R-hat, ESS)


import subprocess
%run ./bayesian/step4_diagnostics.py
%run ./dataframes/truncate_with_ellipsis.py
df = diagnostics_summary(trace)
subprocess.run(['wl-copy'], input=truncate_with_ellipsis(df, 3).to_html().encode())
mean sd hdi_3% ... ess_bulk ess_tail r_hat
mu_PC1 0.011 0.552 -1.052 ... 11203.0 6692.0 1.0
log_sigma_PC1 1.671 0.073 1.537 ... 9556.0 6230.0 1.0
mu_PC2 -0.003 0.151 -0.284 ... 9794.0 6197.0 1.0
... ... ... ... ... ... ... ...
sigma_PC1 5.333 0.391 4.652 ... 9556.0 6230.0 1.0
sigma_PC2 1.463 0.11 1.268 ... 11278.0 6386.0 1.0
sigma_PC3 0.517 0.038 0.45 ... 11880.0 6863.0 1.0

Interpretation

Convergence

Convergence looks excellent across the board: $\hat{R}=1.0$ for every parameter (all 4 chains agree, no stuck or diverging chains), and ESS bulk/tail in the thousands against 8,000 total draws (4 chains × 2,000) — ESS this close to, or exceeding, the raw draw count indicates NUTS sampled this posterior very efficiently. Not surprising given the model: three independent, low-dimensional, well-identified Normal-likelihood groups is about as easy a target as MCMC gets.

Cross-check against Classical PCA

A useful cross-check: the posterior means for $\sigma_i$ line up almost exactly with $\sqrt{\text{eigenvalue}i}$ from Classical PCA's Step 8 — $\sigma{PC1}=5.333$ vs $\sqrt{27.95}=5.29$, $\sigma_{PC2}=1.463$ vs $\sqrt{2.11}=1.45$, $\sigma_{PC3}=0.517$ vs $\sqrt{0.262}=0.51$. This is exactly the outcome aim 3 was looking for: with an uninformative prior, the Bayesian posterior recovers essentially the same numbers as classical PCA, confirming the model and sampler are correctly wired up ahead of Step 7's more formal comparison.

step 2 - trace plots


%run ./bayesian/step4_diagnostics.py
trace_plot_chart(trace, "output/snippets_png/bayesian_step4_trace_plot.png")

Python

filename: step4_diagnostics.py

import arviz as az
import matplotlib.pyplot as plt

'''
convergence diagnostics for the step 3 posterior trace: a summary table of R-hat and
effective sample size per parameter, and trace plots for a visual check.
'''

def diagnostics_summary(trace):
    return az.summary(trace)

def trace_plot_chart(trace, filename):
    az.plot_trace(trace)
    plt.savefig(filename)
    return
R-hat / effective sample size summary table, and trace plots, for the Step 3 posterior draws