Li 2019 - Graphical Horseshoe Model and Gibbs Sampler
Summary
; ; for : , , restricted to the positive-definite cone. A column-by-column block Gibbs sampler (Wang 2012 partitioning + Makalic-Schmidt inverse-gamma augmentation) has all conditionals in closed form and preserves positive definiteness.
Overview
Competitors: graphical lasso (GL): maximise with ; graphical SCAD (no Bayesian form; may not give PD estimates; here selects almost everything); Bayesian graphical lasso (BGL, Wang 2012): double-exponential priors on off-diagonals and exponential on diagonals (), whose MAP is the GL.
Main Content
Precision matrix and partial correlation
. iff ; is the inverse residual variance of regressed on the rest; partial correlation (standard identity).
Graphical horseshoe (GHS) prior (Sec. 2.1)
local, global shrinkage. Density has a spike at the origin (shrinks noise) and heavy Cauchy-type tails (leaves signals nearly unshrunk). The induced marginal prior is proper.
Full conditionals (eq. 2 and Makalic-Schmidt augmentation)
Posterior given scales: , . Partition the last column: , (constant Jacobian). Then
Augmentation: , implies , so , , giving , , , .
Positive definiteness is preserved
If then after updating a last row/column, and the other leading principal minors are unchanged, so (same argument as Wang 2012). Cost per column: inverting a matrix, per sweep column, overall per iteration (the paper states the dominant step is per update).
Algorithm 1 (paper): initialise , , ; for each : draw , , set , , draw , update by block formulas; then draw . (The printed pseudo-code writes the Gamma as “rate = 2/s_ii”, while eq. 2 states rate ; code below follows eq. 2.) MATLAB code: github.com/liyf1988/GHS.
Examples
GHS on a 5-variable toy (numerical check)
, , true has two non-zero off-diagonals (, ). Posterior means after 300 burn-in + 700 draws: , , all other off-diagonals within , diagonal near 1 (checked).
import numpy as np
def ghs(S, n, burnin=300, nmc=700, seed=0):
rng = np.random.default_rng(seed); p = S.shape[0]
Om, Sig, Lam, Nu = np.eye(p), np.eye(p), np.ones((p, p)), np.ones((p, p)); tau2, xi = 1.0, 1.0
out = np.zeros((nmc, p, p))
for it in range(burnin + nmc):
for i in range(p):
idx = np.r_[0:i, i+1:p]
gam = rng.gamma(n/2 + 1, 2/S[i, i]) # rate s_ii/2
O11i = Sig[np.ix_(idx, idx)] - np.outer(Sig[idx, i], Sig[idx, i])/Sig[i, i]
C = np.linalg.inv(S[i, i]*O11i + np.diag(1/(Lam[idx, i]*tau2))); C = (C + C.T)/2
beta = rng.multivariate_normal(-C @ S[idx, i], C)
Om[idx, i] = Om[i, idx] = beta; Om[i, i] = gam + beta @ O11i @ beta
Lam[idx, i] = Lam[i, idx] = 1/rng.gamma(1.0, 1/(1/Nu[idx, i] + beta**2/(2*tau2)))
Nu[idx, i] = Nu[i, idx] = 1/rng.gamma(1.0, 1/(1 + 1/Lam[idx, i]))
W = O11i @ beta; Sig[np.ix_(idx, idx)] = O11i + np.outer(W, W)/gam
Sig[idx, i] = Sig[i, idx] = -W/gam; Sig[i, i] = 1/gam
iu = np.triu_indices(p, 1)
tau2 = 1/rng.gamma((p*(p-1)/2 + 1)/2, 1/(1/xi + np.sum(Om[iu]**2/(2*Lam[iu]))))
xi = 1/rng.gamma(1.0, 1/(1 + 1/tau2))
if it >= burnin: out[it-burnin] = Om
return outPyMC note (E19): putting the horseshoe directly on a precision matrix in a generic sampler leaves the PD cone (no constraint is enforced), which is why GHS needs its column-wise conditional structure; a PyMC alternative is node-wise (neighbourhood) regression with a horseshoe on each regression’s coefficients and an AND/OR rule to symmetrise edges (see Bayesian Gaussian Graphical Models - G-Wishart and Neighbourhood Selection).
Connections
Li 2019 - Kullback-Leibler Risk Bound and Bias Theory gives the theory for the prior’s tails/spike; Joint Priors and Covariance Matrices covers LKJ-based alternatives.