% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vbfa.R
\name{vbfa}
\alias{vbfa}
\title{Variational Bayes partially confirmatory factor analysis}
\usage{
vbfa(
  Y,
  Q,
  ld = FALSE,
  Qe = NULL,
  orthogonal = FALSE,
  bifactor = FALSE,
  general = 1,
  v0 = c(0.01, 0.005, 0.002, 0.001),
  max_it = 5000,
  convChk = FALSE,
  tolVal = 1e-04,
  ld_control = list()
)
}
\arguments{
\item{Y}{Numeric \verb{N x J} data matrix (observations by items). Standardized
internally. Missing continuous responses are handled by deterministic
Gaussian conditional-moment augmentation inside the variational loop.}

\item{Q}{Integer \verb{J x K} design matrix for the loadings: \code{1} = specified
(anchored) loading, \code{0} = fixed zero, \code{-1} = unspecified (estimated by
spike-and-slab). \code{K} is the number of factors.}

\item{ld}{Logical switch for local-dependence (sparse residual) estimation.
\code{FALSE} (default) fits diagonal residuals and ignores \code{Qe} (with a warning
if one is supplied). \code{TRUE} estimates a sparse residual precision by a
graphical spike-and-slab prior solved by QUIC, with the search space given
by \code{Qe}.}

\item{Qe}{Residual design matrix (\verb{J x J}), read only when \code{ld = TRUE}.
Entries \code{1} (freely estimated residual dependence), \code{-1} (uncertain;
selected by spike-and-slab), \code{0} (shrunk to zero). Symmetric; its diagonal
is ignored. The default \code{NULL} means fully exploratory local dependence,
i.e. \code{Qe = matrix(-1, J, J)}.}

\item{orthogonal}{Logical. If \code{TRUE}, the factor correlation is fixed at
the identity (a plain orthogonal factor model; also the engine under a
hand-built bifactor design). Default \code{FALSE} (oblique; factor
correlation estimated). For bifactor models prefer \code{bifactor = TRUE},
which implies orthogonality and keeps \code{K} counting group factors.}

\item{bifactor}{Logical. If \code{TRUE}, fit an orthogonal bifactor model with
\code{Q} supplying only the \strong{group} design (\verb{J x K} for \code{K} group factors):
the general column is added internally according to \code{general}, so the
user-facing \code{K} counts group factors and is directly comparable to an
oblique \code{K}-factor model. Implies orthogonal factors --
\code{bifactor = TRUE} overrides \code{orthogonal = FALSE} (with a message).
Supplying a \code{Q} that already contains an all-specified column is an
error: with \code{bifactor = TRUE} the general column must come from
\code{general}, not from \code{Q}.}

\item{general}{Design of the general column when \code{bifactor = TRUE}: a
scalar or length-\code{J} vector with the usual codes (\code{1} specified, \code{0}
fixed zero, \code{-1} unspecified). The default \code{1} gives the standard
bifactor (every item loads on the general factor). A vector with \code{0}
entries yields bifactor-(S-1)-style designs in which some items carry
no general loading; at least one entry must be \code{1}.}

\item{v0}{Loading-spike variance. A decreasing \strong{vector} gives a
warm-started dynamic regularization path (each stage runs to convergence
and warm-starts the next); a \strong{scalar} gives a single fixed spike. The
default path ends at \code{0.001}; a scalar \code{v0 = 0.001} reproduces the
fixed-spike estimator exactly.

For a \strong{gentler path that aids convergence}, pass a finer, longer,
log-spaced descent starting from a larger \code{v0}, e.g.
\code{v0 = exp(seq(log(0.05), log(0.001), length.out = 10))}. Each stage is
then a small perturbation of the previous one, so its warm start is a good
initialization and it converges quickly and stably. Prefer this when a fit
fails to converge within \code{max_it}, when the loading solution looks
unstable, or for near-singular / strongly regularized models: it navigates
the non-convex spike-and-slab landscape better than a single hard fit, and
is usually preferable to (and often faster than) simply raising \code{max_it}.
Keep the endpoint at your target; log spacing suits the multiplicative
spike.}

\item{max_it}{Maximum variational iterations \strong{per stage}. Default \code{5000}.}

\item{convChk}{Logical; report per-iteration relative error via
\code{\link[=message]{message()}} (so it can be silenced with \code{\link[=suppressMessages]{suppressMessages()}}). Default
\code{FALSE} (quiet).}

\item{tolVal}{Convergence tolerance on the maximum relative error.}

\item{ld_control}{A named list of local-dependence controls, read only when
\code{ld = TRUE}: \code{xi0} (spike-penalty path, units of \code{N}; default
\code{seq(0.1, 1, length.out = 5)}), \code{xi1} (slab penalty, units of \code{N};
default \code{0.01}), \code{diag_penalty} (\code{1} penalizes the precision diagonal with
\code{xi1}, \code{0} leaves it unpenalized), \code{quic_eps}, \code{quic_max_it}, and the Beta
prior parameters \code{a1}, \code{b1} on the local-dependence proportion.}
}
\value{
An object of class \code{c("vbfa", "vbpm_fit")} -- a named list (see
\link{vbpm_fit} for what the class does and does not change) with elements:
\describe{
\item{Lam}{\verb{J x K} posterior mean loadings.}
\item{pi}{Posterior inclusion probabilities of the unspecified loadings
(specified entries are reported as coded in \code{Q}).}
\item{eta}{\verb{N x K} posterior mean factor scores.}
\item{Phi}{Factor correlation matrix; the identity when
\code{orthogonal = TRUE}.}
\item{PsiInv}{Residual precisions; \code{NULL} when \code{ld = TRUE}.}
\item{ELBO}{Evidence lower bound; \code{NA} when \code{ld = TRUE}.}
\item{rho}{Posterior inclusion rate of the unspecified loadings.}
\item{Lam_var}{Posterior variances of the loadings.}
\item{eta_cov}{Posterior covariance of the factor scores.}
\item{Phi_inv_mean}{Posterior mean of the factor precision,
E[Phi^-1].}
\item{iter, flag, time}{Total iterations, \code{1} if the final stage
converged within \code{max_it} (else \code{0}), and elapsed time.}
\item{Q, Qe, orthogonal, ld}{The design matrices and settings the model
was fit with (\code{Qe} is \code{NULL} when \code{ld = FALSE}); read by \code{\link[=fit_stats]{fit_stats()}}
and \code{\link[=print.vbpm_fit]{print.vbpm_fit()}} so they never need repeating.}
\item{bifactor, n_general, general}{Bifactor bookkeeping: whether the
fit declared a bifactor structure, how many general columns it has,
and the general design (\code{NULL} unless \code{bifactor = TRUE}).}
\item{Psi, W, q_star, xi_star, tau}{Local-dependence results (\code{NULL}
when \code{ld = FALSE}): residual precision, its inverse, residual-edge
inclusion probabilities, edge shrinkage, and the LD proportion.}
\item{path}{The \code{v0} schedule (and \code{xi0} under LD) with per-stage
iteration counts.}
\item{preprocess}{Centering and scaling used, \code{n_missing}, the response
type, and \code{missing_mask} -- the mask is stored only when the data
actually contain missing values, and is \code{NULL} otherwise.}
\item{sample_cov}{The sample correlation matrix the fit statistics use.}
}

Every quantity appears exactly once: as of 0.7.0 the fit no longer
carries \verb{$coefficients}, \verb{$design}, \verb{$posterior}, or \verb{$settings}, which
duplicated the elements above.
}
\description{
Fits a partially confirmatory factor-analytic measurement model by
regularized mean-field variational Bayes. Loadings on \emph{specified} factors
are anchored by the design matrix \code{Q}; loadings on \emph{unspecified} factors are
selected from the data through continuous spike-and-slab priors. Optional
features are a warm-started dynamic regularization path, an orthogonal
bifactor parameterization, and sparse residual (local-dependence)
estimation.
}
\section{Notes}{

The diagonal-residual estimator is \strong{deterministic} (fixed initialization,
no random numbers), so results are reproducible without a seed; there is no
\code{rseed} argument. (The local-dependence branch's QUIC solver shuffles its
active set with the RNG, but that is a convex solve, so the shuffle order
does not change the solution.)

Missing continuous responses are supported (see \code{Y}). Support for
categorical or mixed responses is not yet implemented.

Under local dependence \code{ELBO} is \code{NA} by design, and this is not a
placeholder: the residual precision and the mixing proportion are point
updates rather than variational factors, so no single joint mean-field
bound over all unknowns is defined. The quantities that \emph{are} defined are
returned under their own names --- \code{objective} (the terminal VECM objective,
with \code{objective_type = "vecm"}) and \code{ELBO_conditional} (the conditional
bound given the terminal precision and mixing proportion). Use \code{objective}
for model comparison, and only across fits sharing one \code{objective_type}.
}

\examples{
## partially confirmatory: two anchors per factor, the rest exploratory
sim <- sim_fa(N = 200, K = 3, ipf = 6, lam = .7, lac = .3, rseed = 1)
Q <- matrix(-1L, ncol(sim$dat), 3)
for (k in 1:3) { a <- which(rep(1:3, each = 6) == k)[1:2]; Q[a, ] <- 0; Q[a, k] <- 1 }
fit <- vbfa(sim$dat, Q)
fit$flag                    # 1 if converged
round(fit$Lam, 2)           # loadings
round(fit$pi, 2)            # posterior inclusion probabilities

\donttest{
## orthogonal bifactor, preferred form: Q holds only the GROUP design and
## K counts group factors (comparable to an oblique K-factor model)
fb <- vbfa(sim$dat, Q, bifactor = TRUE, v0 = .001)  # fixed spike: fast demo
fb                          # prints "1 general + 3 group factors"
fb$Phi                      # identity by construction
## equivalent long form: vbfa(sim$dat, cbind(1L, Q), orthogonal = TRUE)

## local dependence: simulate correlated residuals, then set ld = TRUE
simLD <- sim_fa(N = 300, K = 3, ipf = 6, lam = .7, lac = .3, ecr = .3,
                rseed = 2)
fLD <- vbfa(simLD$dat, Q, ld = TRUE, max_it = 300,
            tolVal = 1e-3)
## largest recovered residual edges vs the planted ones
Poff <- abs(fLD$Psi); Poff[lower.tri(Poff, diag = TRUE)] <- 0
which(Poff >= sort(Poff, decreasing = TRUE)[3], arr.ind = TRUE)
simLD$ofd_ind

## empirical illustration: NLSY 1997, 27 items treated as continuous.
## A 500-row subset keeps the example quick; the vignette fits all 3,458.
data(nlsy27)
Yn <- as.matrix(nlsy27$dat)[1:500, ]
sum(is.na(Yn))            # incomplete cells, imputed in-loop
fn <- vbfa(Yn, nlsy27$Q)
round(fn$Lam, 2)
}

}
\references{
Chen, J., Guo, Z., Zhang, L., & Pan, J. (2021). A partially confirmatory
approach to scale development with the Bayesian Lasso. \emph{Psychological
Methods}, 26(2), 210-235. \doi{10.1037/met0000293}

Chen, J. (2021). A generalized partially confirmatory factor analysis
framework with mixed Bayesian Lasso methods. \emph{Multivariate Behavioral
Research}, 57(6), 879-894. \doi{10.1080/00273171.2021.1925520}

Jin, Y., & Chen, J. (2025). Regularized variational approximation for
partially confirmatory factor analysis. \emph{Structural Equation Modeling: A
Multidisciplinary Journal}, 32(3), 437-449.
\doi{10.1080/10705511.2024.2432612}

Jin, Y., Chen, J., Yan, Z., & Zhang, Y. (2026). Sparse residual estimation
in partially confirmatory factor analysis. \emph{PsyArXiv preprint}.
\doi{10.31234/osf.io/dehtv_v2} --- the warm-started \code{v0} path and the
\code{ld = TRUE} sparse-residual (local dependence) branch.

Rockova, V., & George, E. I. (2018). The spike-and-slab LASSO.
\emph{Journal of the American Statistical Association}, 113(521), 431-444.
\doi{10.1080/01621459.2016.1260469}
}
