Nested-Laplace integration over random-effect covariances
Source:R/nested_laplace_re_cov.R
tulpa_re_cov_nested.RdFor one or more random-effects terms (e.g. (1 + x | g), (1 + x || g), or
several terms together), integrate the Laplace marginal likelihood over the
random-effect covariances Sigma instead of fixing them at point estimates.
Reports weighted posterior summaries (mean, SD, median, 2.5\
Sigma and its derived scale (sigma_i) and correlation (rho_ij)
parameters, marginalizing the joint posterior over a Sigma-grid.
This corrects the plug-in-MAP ("summary") bias: the mode of a skewed variance-component marginal is biased low relative to its median, so the headline summary should be the marginalized median, not the mode.
Usage
tulpa_re_cov_nested(
y,
n_trials = NULL,
X,
re_terms,
family = "binomial",
phi = 1,
phi2 = NULL,
prior_sigma = NULL,
eta = NULL,
hyperprior = c("proper", "flat"),
log_prior_theta = NULL,
beta_prior = NULL,
offset = NULL,
weights = NULL,
n_quad = 1L,
X_zi = NULL,
zi_prior_sd = 2.5,
control = list()
)Arguments
- y, n_trials, X, family, phi
Passed to
tulpa_laplace()for the inner solve.n_trials = NULLdefaults to 1 (binary / single-trial).- re_terms
Either a single random-effect term or a list of them. Each term is a list with
idx(1-based group index per observation),n_groups,n_coefs(c),Z(then_obs x cRE design, e.g.cbind(1, x)for(1 + x | g); only required whenc > 1), andcorrelated(TRUEfor a fullSigma,FALSEfor a diagonal one; defaults toTRUE). An optionallabel/group_varnames the block in the output. AnyL/cov/sigmafield is ignored –Sigmais what this function integrates over.- phi2
Optional second dispersion, threaded into every inner
tulpa_laplace()solve: the Student-t degrees of freedom (family = "t", default 4 whenNULL) or the Tweedie variance power (family = "tweedie", required – a defaulted power would be a statistical decision the caller never made). Aphi2supplied for any other family errors rather than being ignored. It is conditioned on: the integration is over the random-effect covariances, not overphi2.- prior_sigma, eta
Hyperparameters of the PC + LKJ prior used when
hyperprior = "proper"(seere_cov_pc_lkj_prior()):prior_sigma = c(U, alpha)withP(sigma_i > U) = alpha(NULL, the default, isc(3, 0.01)) and LKJ shapeeta(NULLis 2). Ignored whenhyperprior = "flat"orlog_prior_thetais supplied.- hyperprior
"proper"(default) or"flat"."proper"builds the PC + LKJ prior fromprior_sigma/eta, the proper prior every other scale axis of the engine carries by default."flat"integrates withlog_prior_thetathe zero function (flat in log(theta)); that prior is improper, so the fit then reports no evidence. Ignored whenlog_prior_thetais supplied.- log_prior_theta
Optional
function(theta)returning a scalar log prior density on the full stacked parameter vector, overridinghyperpriorentirely. DefaultNULL, which defers tohyperprior.- beta_prior
Optional Gaussian prior on the fixed effects, threaded into every inner
tulpa_laplace()solve (list(mean, sd)).NULL(default) keeps the weak built-in prior.- offset
Optional observation-level offset on the linear predictor (length
length(y)), e.g.log(exposure)for a rate model. Not supported withn_quad > 1, which errors rather than dropping it.- weights
Optional non-negative observation weights (length
length(y)), each scaling its row's log-likelihood in every innertulpa_laplace()solve, so the covariance is integrated under the weighted likelihood. Not supported withn_quad > 1, which errors rather than dropping them.- n_quad
Quadrature order for the inner marginal.
1(default) uses the joint-field Laplace inner solve (tulpa_laplace()).> 1refines the inner marginal withn_quad-point adaptive Gauss-Hermite quadrature (thetulpa_re_aghq()debias applied inside theSigmaintegration), reducing the small-cluster variance attenuation for binary / low-count data. AGHQ requires a single shared grouping factor (the per-group integral must factorize); with crossed RE termsn_quad > 1errors. When AGHQ is used the fixed effects are integrated, so the reported fixed-effect posterior is the marginal (ML-II) one rather than the joint-mode (PQL) estimate.- X_zi
Optional zero-inflation design matrix (
length(y)rows), making the model a two-process mixture: each observation is a structural zero with probabilityplogis(X_zi beta_zi)and otherwise followsfamily. Paired with a zero-truncated family it is the hurdle model. The random effects enter the count predictor only, and the integration runs over the same covariance coordinates – the mixture changes the inner solve, not the parameters being integrated over. The ZI coefficients are reported alongside the count ones incoef()/vcov(), so the fixed block isncol(X) + ncol(X_zi)wide. Needsn_quad = 1: the adaptive Gauss-Hermite inner marginal runs through a single-predictor oracle.- zi_prior_sd
Prior SD on
beta_zi, keeping the logit identified where a level carries no zeros (the likelihood alone would send it to-Inf). Ignored whenX_ziisNULL.- control
A named list of numerical / tuning knobs (statistical arguments stay in the signature above). Recognized entries:
integration: node layout,"ccd"(default, central-composite design, scales to larger total parameter count) or"grid"(full tensor product).n_per_axis: points per parameter axis in the tensor grid (default 5); used only whenintegration = "grid".span: half-width of the tensor grid in posterior standard deviations per whitened axis (default 3); grid only.n_draws: posterior draws of the fixed effects synthesized from the node mixture (default 2000), exposed asdrawsfor the generictulpa_fitmethods. TheSigmaposterior is summarized directly from the integration nodes inposterior, independent ofn_draws.seed: optional integer seed for the fixed-effect draw synthesis.diagnose_k: ifTRUE(default), compute the outer Pareto k-hat accuracy diagnostic for the Gaussian proposal over the hyperparameters, returned aspareto_k. Several proposal candidates are scored and the best is kept:pareto_k_proposal_sourcenames which one produced the reported number andpareto_k_first_passis the k-hat of the proposal exactly as the mode-find placed it, before refinement. A large gap between the two says the placement is poor even where the verdict is fine – on a small-group binary fit the first pass runs 15 to 49 where the reported k-hat is 0.3 to 0.8.k_samples: importance draws for thediagnose_kestimate (default 500). It is a precision knob: the GPD tail size is held at the fraction that default budget implies, so raising it supplies more tail ratios for the SAME estimand rather than moving the fit to a deeper quantile of the weight distribution (gcol33/tulpa#631). Each draw is one inner Laplace solve, so this sets the diagnostic's cost; the draws are solved in one compiled batch, each started from the mode at the proposal centre.k_threads: thread width for those draws (NULL, the default, followsn_threads;"auto"takes the physical performance cores; an integer sets it,1Lforcing serial). Each draw is solved single-threaded and from the same start, so the k-hat does not depend on the width.k_tail_points: expert override for that tail size, in upper-tail order statistics. Silently capped at 20% of the draws, beyond which body ratios enter the tail and bias the shape.max_iter,tol,n_threads: inner-solve controls (seetulpa_laplace()).outer_maxit: iteration budget for the mode-finding step that centres the integration grid (default 500). Applies to the Nelder-Mead simplex used from two parameters up; the one-parameter case is bracketed by Brent. Exhausting the budget warns, since the nodes are then centred on wherever the optimizer stopped.checkpoint: node checkpoint/resume speclist(path = , resume = ). Each completed CCD / grid node (one inner Laplace solve) is cached topath; aresume = TRUErun loads the finished nodes and re-solves only the rest.resume = FALSEstarts fresh. A file written for different data, layout, or grid is rejected (fingerprint mismatch). DefaultNULL(off).subspace_debias: subspace debias,FALSEby default.TRUEtakes every default; a list overridesband(the inner-reliability floor a coordinate is selected at, default"ok"),idx(pin the corrected set explicitly, skipping the selector),probe(the latent indices scored, default the fixed effects),closure(FALSE,TRUE, or a partial-correlation threshold: grow the set by the precision-graph neighbours it is strongly coupled to),closure_max, and the sampler budgetn_iter/warmup/thin. When the selected set is non-empty, each integration node reports the selected fixed-effect coordinates from a Metropolis sample of the exact conditional along the Gaussian-conditional-mean surface, and the rest from the Gaussian conditional given them; an EMPTY set leaves the fit bit-for-bit identical to the plain path. What was selected is recorded insubspace_debiason the returned fit.
Value
A list with:
posterior: data frame with one row per parameter and columnsmean,sd,median,ci_lo,ci_hi. Parameter names aresigma_i,rho_ij,Sigma_ijfor a single block, prefixed by the block label (g.sigma_1, ...) when there are several blocks. Diagonal blocks report norho.map: the plug-in-mode summary attheta_hat(a singlelist(Sigma, sigma, rho)for one block, or a named list of them).Sigma_mean: the weighted posterior mean ofSigma(a matrix for one block, or a named list of matrices).beta,draws,means,param_names,process_info: the fixed-effect posterior from the node mixture (drivescoef/confint/vcov/summary).re_nodes,re_var_nodes: the per-group random-effect posterior at each integration node – conditional mean and marginal variance of every (block, group, coefficient), one row per node.ranef()reports theweights-mixture of them.NULLatn_quad > 1, whose inner marginal integrates each group out instead of conditioning on it; that fit carriesranef_unavailable(the reason) in their place.re_debias_draws,re_debias_idx: present when the subspace debias selected a random-effect coordinate. The sampled draws of those coordinates on the node mixture the fixed-effect draws use, and their positions within the random-effect block.ranef()reports those rows empirically and the rest from the Gaussian mixture, recording which in itssourcecolumn.theta_hat,theta_grid,weights,log_marginal,n_grid,layout,n_blocks,n_coefs(vector of per-blockc).subspace_debias: present only whencontrol$subspace_debiaswas set.idxare the corrected latent coordinates,bandsthe per-probed-index reliability table they were read from,closure_addedwhat the coupling closure added, andacceptthe per-node Metropolis acceptance rate.
Details
Each term is one covariance block. A correlated block ((1 + x | g)) is
a full Sigma = L L' parameterized by its lower Cholesky factor in
log-Cholesky coordinates (the log-diagonal and the strictly-lower entries of
L, c(c+1)/2 values for a c-coefficient block), which keeps Sigma
positive definite for every coordinate. An uncorrelated block
((1 + x || g)) is a diagonal Sigma parameterized by its c log standard
deviations. A scalar (1 | g) term is the degenerate c = 1 block. Several
blocks stack their parameters into one integration vector; a single-term
model is the length-1 case.
Integration nodes live in the whitened stacked-parameter space, centred at
the joint marginal-likelihood mode and rotated/scaled by the Cholesky of the
mode's posterior covariance (solve(Hessian)), so points track the posterior
ridge. Two node layouts are available via integration:
"ccd"(default): a central-composite design (ccd_grid()) of1 + 2k + 2^(k-q)points for the totalk = sum_blocksparameters, with the corrected R-INLA design weights (ccd_weights()). Scales polynomially ink, where the tensor grid is exponential."grid": the fulln_per_axis^ktensor product with uniform cell weights – denser and more robust to a non-Gaussian whitened posterior, but only tractable for smallk.
Each node k contributes integration weight proportional to
Delta_k * exp(log_marginal(Sigma_k) + log_prior_theta(theta_k)), following
the INLA convention int ~ sum_k Delta_k pi(theta_k).
The two layouts also decide how the reported median and 2.5\
of each derived quantity are read off the nodes. A tensor grid's uniform
cells discretize the posterior density, so the cumulative node weights are a
CDF and the summary is the weighted quantile. A CCD is a moment rule: its
nodes sit where they reproduce the integrand's first two moments and carry no
probability mass of their own, so the summary is moment-matched instead –
the first two weighted moments on each quantity's own coordinate (log for a
scale or a variance, atanh for a correlation, the identity for a covariance)
define a Gaussian there whose quantiles are mapped back. Scale intervals are
therefore positive and asymmetric, and correlation intervals stay inside
(-1, 1). The mean and sd columns are the weighted moments under either
layout.
By default (hyperprior = "proper") log_prior_theta is the
weakly-informative PC + LKJ hyperprior, built per block by
re_cov_pc_lkj_prior() and summed over blocks (PC prior on each marginal SD
via prior_sigma, LKJ prior on each correlated block's correlation matrix via
eta), expressed in the same parameterization with the exact
change-of-variables Jacobian. hyperprior = "flat" makes it the zero
function, flat in log(theta). The likelihood it multiplies is the inner
Laplace marginal, which integrates the fixed effects out together with the
random effects rather than profiling them, so under "flat" the node centre
theta_hat is a restricted (REML-type) estimate – REML for a gaussian
response, agreeing with glmmTMB(..., REML = TRUE) rather than with the ML
fit of lme4::glmer() otherwise (see tulpa_eb()). Supply a custom log_prior_theta
function to override either default (then prior_sigma / eta /
hyperprior are ignored); it must act on the full stacked parameter vector.
tulpa_eb() shares this same objective and the same default, so
tulpa_eb()$theta_hat and tulpa_re_cov_nested()$theta_hat stay the same
estimate on the same data under either setting.
References
Rue, Martino & Chopin (2009). Approximate Bayesian inference for latent Gaussian models by using integrated nested Laplace approximations. JRSS-B 71(2):319-392. Lewandowski, Kurowicka & Joe (2009). Generating random correlation matrices based on vines and extended onion method. Journal of Multivariate Analysis 100(9):1989-2001.
See also
tulpa_laplace() for the inner solve; tulpa_nested_laplace() for
the analogous outer integration over spatial / temporal prior
hyperparameters.
Examples
# \donttest{
set.seed(1)
G <- 20L; per <- 12L; n <- G * per
grp <- rep(seq_len(G), each = per); x <- rnorm(n)
b <- cbind(rnorm(G, 0, 0.7), rnorm(G, 0, 0.5)) # random intercept + slope
eta <- -0.2 + 0.5 * x + b[grp, 1] + b[grp, 2] * x
y <- rbinom(n, 1L, plogis(eta))
re_term <- list(idx = grp, n_groups = G, n_coefs = 2L, Z = cbind(1, x),
correlated = TRUE)
fit <- tulpa_re_cov_nested(y, rep(1L, n), cbind(1, x), re_term,
family = "binomial")
fit$Sigma_mean # marginalized RE covariance
# }