Skip to contents

Three intents, three models

A lavaan model specification expresses one of three intents about the observed-variable means, and INLAvaan gives each a distinct Bayesian treatment:

You write Meaning Treatment
meanstructure = TRUE means are modelled intercepts 𝛎\boldsymbol\nu get priors and are estimated
meanstructure = FALSE means are not of interest saturated means get flat priors and are marginalised analytically
x1 ~ 0*1 etc. means are truly zero fixed at zero, no parameters

The middle row deserves explanation. Classically, meanstructure = FALSE fits the covariance structure only: the likelihood is profiled, with each mean plugged at its sample value. Profiling is not a Bayesian operation — a posterior built from a profiled likelihood has no generative interpretation. INLAvaan instead reads the same model specification as saturated means with flat priors, integrated out. The integral is available in closed form: with 𝐀=i(𝐲i𝐲)(𝐲i𝐲)\mathbf{A} = \sum_i (\mathbf{y}_i - \bar{\mathbf{y}})(\mathbf{y}_i - \bar{\mathbf{y}})',

logp(𝐘𝚺)=n12log|𝚺|12tr(𝚺1𝐀)p2logn+const, \log p(\mathbf{Y} \mid \boldsymbol\Sigma) = -\frac{n-1}{2}\log|\boldsymbol\Sigma| - \frac{1}{2}\operatorname{tr}\left(\boldsymbol\Sigma^{-1}\mathbf{A}\right) - \frac{p}{2}\log n + \text{const},

the profiled likelihood with n1n-1 in place of nn. This is the same treatment R-INLA applies to any included fixed effect: its default intercept prior is exactly flat (prec.intercept = 0), and the intercept is integrated out analytically as part of the latent Gaussian field. Relative to the profiled fit, posterior modes of variance parameters recalibrate by the factor n/(n1)n/(n-1) — a small, principled shift.

Note that meanstructure = FALSE is not a shortcut for fixing intercepts at zero. Zero intercepts are a falsifiable restriction: the sample means enter the likelihood and are tested against zero, which on uncentred data badly distorts the covariance fit. meanstructure = FALSE discards the sample means entirely; the covariance estimates are identical to those from a model with freely estimated intercepts.

Two practical notes. Two-level models require a mean structure (the between-level statistics are the cluster means), so an explicit meanstructure = FALSE with cluster = warns and fits with meanstructure = TRUE. With missing data, missing = "ML" likewise implies a mean structure.

Predictive quantities

Under the marginalised reading the saturated means are not discarded — they have an exact posterior, 𝛎𝚺,𝐘N(𝐲,𝚺/n)\boldsymbol\nu \mid \boldsymbol\Sigma, \mathbf{Y} \sim N(\bar{\mathbf{y}}, \boldsymbol\Sigma/n). Everything downstream conditions on it or integrates it: loo() and waic() score each unit by the exchangeable leave-one-out conditional i=logφ(𝐲i;𝐲i,nn1𝚺), \ell_i = \log \varphi\left(\mathbf{y}_i;\, \bar{\mathbf{y}}_{-i},\, \tfrac{n}{n-1}\,\boldsymbol\Sigma\right), the exact case-deletion predictive (note the mean-estimation discount built into both arguments); factor scores condition on 𝐲\bar{\mathbf{y}}; and posterior predictive replicates from sampling() and simulate() draw the means from their posterior, inflating the predictive covariance to (1+1n)𝚺(1 + \tfrac1n)\boldsymbol\Sigma exactly as estimated intercepts would. Models with exogenous covariates (fixed.x = TRUE, the lavaan default — including binary covariates, whose moments stay frozen at their sample values and are never given a Gaussian model) are fully supported: the mean marginalisation factorises blockwise, and loo()/waic() score each unit by the difference of two exchangeable conditionals, with the frozen-covariate term entering as an exact constant.

Worked example: a measurement invariance ladder

The two mean treatments meet in measurement invariance testing. The first two rungs are covariance-only; the third constrains intercepts across groups, which forces modelled means — there is no “marginalised scalar invariance”, because constrained means are no longer saturated.

model <- "
  visual  =~ x1 + x2 + x3
  textual =~ x4 + x5 + x6
  speed   =~ x7 + x8 + x9
"
dat <- lavaan::HolzingerSwineford1939

fit_configural <- acfa(model, dat, group = "school",
                       meanstructure = FALSE, verbose = FALSE)
fit_metric <- acfa(model, dat, group = "school",
                   meanstructure = FALSE, group.equal = "loadings",
                   verbose = FALSE)
fit_scalar <- acfa(model, dat, group = "school",
                   group.equal = c("loadings", "intercepts"),
                   verbose = FALSE)

When are these models comparable?

Within the covariance-only rungs, marginal log-likelihoods and Bayes factors are fine: both models carry the same flat-prior mean treatment, so its arbitrary normalisation cancels.

compare(fit_configural, fit_metric)
#> Bayesian Model Comparison (INLAvaan)
#> Models ordered by marginal log-likelihood
#> 
#>           Model npar Marg.Loglik   logBF      DIC     pD
#>      fit_metric   36   -3846.370   0.000 7504.664 36.177
#>  fit_configural   42   -3870.567 -24.198 7507.469 41.490

Across the metric–scalar boundary they are not: an improper flat prior is only defined up to a constant cc, the marginal likelihood scales with cpc^{\,p} per group, and against a model with proper-prior means that constant is orphaned — the “Bayes factor” becomes an artefact of a normalisation convention (and even proper-but-vague intercept priors leave it hostage to the prior width, the Lindley–Bartlett phenomenon). compare() warns when fits mix the two mean treatments.

The leave-one-out conditionals, by contrast, are proper under both treatments — p(𝐲i𝐘i)=p(𝐘)/p(𝐘i)p(\mathbf{y}_i \mid \mathbf{Y}_{-i}) = p(\mathbf{Y})/p(\mathbf{Y}_{-i}) cancels the flat-prior constant — so ELPD comparisons are valid across the boundary, and compare(..., loo = TRUE) is the honest cross-treatment instrument (it still warns you to read only the ELPD columns, since the marginal log-likelihood columns remain in the table). This works for multigroup fits too — without a mean structure the exchangeability transformation applies within each group — which makes LOO the instrument that spans the whole measurement-invariance ladder; see the multigroup article for that workflow.

fit_f <- acfa(model, dat, meanstructure = FALSE, verbose = FALSE)
fit_t <- acfa(model, dat, meanstructure = TRUE, verbose = FALSE)
compare(fit_f, fit_t, loo = TRUE)
#> Warning: Comparing fits with and without a mean structure: marginal log-likelihoods,
#> Bayes factors, and DIC are not comparable across the two mean treatments (the
#> flat-prior normalisation of the saturated means does not cancel).
#> ℹ Interpret only the ELPD columns; leave-one-out conditionals are proper under
#>   both treatments.
#> Bayesian Model Comparison (INLAvaan)
#> Models ordered by ELPD (Taylor LOO)
#> elpd_diff/se_diff are paired differences vs the best model
#> 
#>  Model npar Marg.Loglik   logBF      DIC     pD      ELPD     SE  p_loo
#>  fit_f   21   -3841.139   0.000 7552.612 20.583 -3769.087 42.999 23.658
#>  fit_t   30   -3885.211 -44.072 7535.527 29.756 -3769.109 42.945 32.433
#>  elpd_diff se_diff
#>      0.000   0.000
#>     -0.022   0.301

The two ELPDs agree closely: both estimate ilogp(𝐲i𝐘i)\sum_i \log p(\mathbf{y}_i \mid \mathbf{Y}_{-i}), and the models differ only in whether the means are estimated under proper priors or marginalised under flat ones.