A MIMIC (multiple-indicators multiple-causes) model adds a structural
part to the factor model: observed covariates \(X\) predict the factors, which in turn
produce the item responses \(Y\).
vbmimic() implements the extended MIMIC model of Jin &
Chen (2025, Multivariate Behavioral Research), whose
contribution is to regularize both parts:
spike-and-slab priors select unspecified entries of the measurement
design Q_A (items on factors, J x K)
and of the structural design Q_B (factors on
covariates, K x P). Both matrices use the same
-1/0/1 codes as vbfa().
With the default settings, vbmimic() reproduces the
published estimator exactly.
sim_lvm() (absorbed from the LAWBL package) generates
the data. Supply the structural coefficients as a matrix — a sparse
design where each factor is predicted by its own covariates is both
realistic and estimable:
B <- matrix(0, 3, 9)
for (k in 1:3) B[k, (k * 3 - 2):(k * 3)] <- .3 # 3 covariates per factor
sim <- sim_lvm(N = 500, K = 3, J = 18, P = 9, b = B, phx = 0, rseed = 1)
Y <- sim$dat[, 1:18] # items first ...
X <- sim$dat[, 19:27] # ... covariates last(A scalar b would make every covariate predict
every factor, which quickly leaves no disturbance variance —
sim_lvm() stops with an informative error if the design is
infeasible.)
One modelling caution, learned the empirical way: with
both Q_A and Q_B fully
exploratory the model converges cleanly but the solution is rotationally
ambiguous — factors can merge or swap. Anchoring either part resolves
it. Here we anchor two items per factor in the measurement part and
leave the whole structural part to the data:
## Q_A is an AZ (anchor-zero) design: each anchor is specified (1) on its own
## factor and fixed to zero on the other two
Q_A <- matrix(-1L, 18, 3)
for (k in 1:3) {
a <- which(rep(1:3, each = 6) == k)[1:2]
Q_A[a, ] <- 0L
Q_A[a, k] <- 1L
}
Q_B <- matrix(-1L, 3, 9) # structural selection is the questionAZ (anchor-zero) and AO (anchor-only) are the two anchor conventions
vbpm’s documentation uses throughout: AO codes each
anchor’s intended cell 1 and leaves its cells on the other
factors -1, while AZ additionally fixes those cells to
0. AZ is the stronger claim, and it is what anchors the
measurement part here; vignette("bifactor") compares the
two.
fit <- vbmimic(Y, X, Q_A, Q_B)
fit
#> vbmimic: regularized VB MIMIC model
#> 18 items, 3 factors, 9 covariates, N = 500
#> converged in 19 iterations (0.19 secs)
#> ELBO: NA (not available for this model)
#> active unspecified loadings (PIP >= 0.5): 12 of 36
#> active structural coefficients (PIP >= 0.5): 11 of 27
#>
#> Components: model, call, nobs, nitem, nfactor, converged, A, B, pi_A, pi_B, Q_A, Q_B, eta, Phi, Sig, U, V, rho, theta, A_var, B_var, iter, flag, time, ELBO, objective, objective_type, standardize, preprocess, path
#> Access them with $ as usual; see ?vbpm_fit.The structural question — which covariates predict which
factors? — is answered by B and its posterior
inclusion probabilities pi_B:
round(fit$B, 2)
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#> [1,] 0.25 0.30 0.32 0.00 0.01 0.00 0.02 0.00 -0.01
#> [2,] 0.00 0.01 -0.18 0.39 0.34 0.30 0.02 -0.01 0.00
#> [3,] 0.03 -0.02 0.01 -0.14 -0.01 -0.01 0.38 0.30 0.30
round(fit$pi_B, 2)
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#> [1,] 1.00 1.00 1.00 0.03 0.03 0.03 0.04 0.03 0.03
#> [2,] 0.03 0.03 1.00 1.00 1.00 1.00 0.04 0.03 0.03
#> [3,] 0.05 0.04 0.03 1.00 0.03 0.04 1.00 1.00 1.00Compare PIP-based selection with the generating design:
selected <- fit$pi_B >= .5
table(truth = B != 0, selected = selected)
#> selected
#> truth FALSE TRUE
#> FALSE 16 2
#> TRUE 0 9Read that table both ways. All nine generating coefficients are
selected — no false negatives — but so are two of the eighteen true
zeros, and not marginally: both sit at PIP 1.00 in the matrix above
(B[2, 3] and B[3, 4], each a factor picking up
a covariate from a neighbouring block). Exploratory structural selection
at this N is therefore not free of false positives, and a
PIP at the ceiling is not on its own evidence that a coefficient is
real. Magnitude is the useful second filter here: the two false
positives are estimated at -0.18 and -0.14, below every one of the nine
true coefficients, whose smallest estimate is 0.25 against a generating
value of 0.30.
The measurement side reads exactly as in vbfa():
round(fit$A, 2)[1:6, ]
#> [,1] [,2] [,3]
#> [1,] 0.64 0.00 0.00
#> [2,] 0.63 0.00 0.00
#> [3,] 0.62 -0.02 -0.01
#> [4,] 0.62 0.00 0.01
#> [5,] 0.59 0.01 -0.01
#> [6,] 0.71 0.01 -0.03
round(fit$Phi, 2) # factor correlations, from the disturbances
#> [,1] [,2] [,3]
#> [1,] 1.00 -0.05 -0.03
#> [2,] -0.05 1.00 -0.01
#> [3,] -0.03 -0.01 1.00vbmimic() accepts NA in Y; a
handful of missing item responses is enough to demonstrate it:
Ym <- Y
Ym[cbind(1:20, rep(1:4, each = 5))] <- NA
sum(is.na(Ym))
#> [1] 20
fitm <- vbmimic(Ym, X, Q_A, Q_B)
fitm$preprocess$n_missing
#> [1] 20
## structural and measurement recovery are essentially unaffected
max(abs(fitm$B - fit$B))
#> [1] 0.002613604
max(abs(fitm$A - fit$A))
#> [1] 0.005325698The residual covariance here is diagonal (vbmimic() has
no LD branch), so a missing response is replaced in-loop by its
conditional mean eta_i A', with the conditional variance
1 / V_j carried into the residual sum of squares — the same
conditional-moment logic as vbfa()’s diagonal case,
simplified because there is no cross-item residual covariance to
condition on. As with vbfa(), this in-loop treatment is
valid under missing at random (MAR) (Chen, 2021).
X must be complete. Covariates are
conditioned on, not modelled, so there is no distribution to impute them
from:
v0 path. As in vbfa(), a
decreasing vector gives a warm-started regularization path over both
parts; the scalar default 0.001 is the published fixed
spike.standardize. The default
FALSE is the published estimator’s behaviour.
vbfa() by contrast always standardizes internally; set
standardize = TRUE for the analogous behaviour.vbfa(), the
estimator consumes no random numbers — no seed argument, bit-identical
reruns.fit$ELBO is
NA. fit_stats() accepts a vbmimic
fit (it dispatches to a dedicated method) but returns a deliberately
limited result: NA for every SEM-like index
(RMSEA, BIC, ELBO,
objective, …) and a single n_active_coef — the
count of soft-selected measurement plus structural coefficients, not a
full parameter count, and not to be fed to an information criterion.
pefa() sweeps vbfa() from one backbone
Q0; it does not sweep MIMIC models.