Skip to contents

Package overview

Structural equation models (SEMs) rarely reject the null hypothesis that there is no model misspecification. One explanation for this problem is that covariance structures are influenced by major factors which we can hypothesize about and minor factors which we cannot predict a-priori, e.g. MacCallum and Tucker (1991).

Goals

The goal of minorbsem is to facilitate fitting Bayesian SEMs that estimate the influence of minor factors on the covariance matrix, following the approach in Uanhoro (2023). Briefly, the method estimates all residual covariances with priors that shrink them towards zero, and the model returns the magnitude of the influence of minor factors.

minorbsem also fits random-effects meta-analytic confirmatory factor analyses (CFAs) that capture the influence of minor factors, according to the approach outlined by Uanhoro (2022).

Permitted models and supported data types

The package only fits a limited number of model configurations:

  • CFA, allowing cross-loadings (which may be automatically estimated), correlated errors terms, and fully oblique or orthogonal factors (useful for fitting bifactor models)
  • SEMs allowing latent regressions (only), cross-loadings, and correlated error terms.

However, the package does not currently support fitting: - MIMIC, - multi-group models, - multilevel models, or - models with specially constrained parameters (e.g., setting two parameters equal).

The meta-analysis models are only for the CFA configurations.

All data are assumed multivariate normal, i.e. no binary, ordinal models.

Installation

Install minorbsem:

install.packages(
  'minorbsem',
  repos = c(
    'https://jamesuanhoro.r-universe.dev', 'https://cloud.r-project.org'
  )
)

A reasonably complete demonstration

library(minorbsem)
# Basic Holzinger-Swineford model
syntax_1 <- "
F1 =~ x1 + x2 + x3
F2 =~ x4 + x5 + x6
F3 =~ x7 + x8 + x9"
# Expect a summary table output
fit_1 <- minorbsem(syntax_1, HS)

# Save output table to html file, see: ?pretty_print_summary for more options
pretty_print_summary(fit_1, save_html = "baseline_model.html")

# Histogram of parameters, see: ?parameter_hist for arguments
parameter_hist(fit_1)

# Traceplot of parameters, see: ?parameter_trace for arguments
parameter_trace(fit_1)

# Examine all standardized residual covariances
plot_residuals(fit_1)
plot_residuals(fit_1, type = "range")

Model comparisons

Fit a second model that estimates all cross-loadings and shrinks them to 0 using a global-local prior (simple_struc = FALSE).

Then compare both models using the Leave-One-Out (LOO) method, using the loo package: install.packages("loo").

fit_2 <- minorbsem(syntax_1, HS, simple_struc = FALSE)

# Compute case wise log-likelihood
# exclude minor factor influences or else both models will fit data equally
ll_mat_1 <- casewise_log_likelihood(fit_1, include_residuals = FALSE)
ll_mat_2 <- casewise_log_likelihood(fit_2, include_residuals = FALSE)
chain_id <- posterior::as_draws_df(fit_1@stan_fit)$.chain

# loo for model 1
loo_1 <- loo::loo(
  ll_mat_1,
  r_eff = loo::relative_eff(ll_mat_1, chain_id = chain_id)
)
print(loo_1)

# loo for model 2
loo_2 <- loo::loo(
  ll_mat_2,
  r_eff = loo::relative_eff(ll_mat_2, chain_id = chain_id)
)
print(loo_2)

# Compare both models
print(loo::loo_compare(loo_1, loo_2), simplify = FALSE)

Additional examples

Different methods to capture the influence of minor factors

Default method above is method = "normal" assuming standardized residual covariances are on average 0 and vary from 0 in continuous fashion.

## Fit same model as above but use global-local prior to estimate
# minor factor influences
fit_gdp <- minorbsem(syntax_1, HS, method = "GDP")
plot_residuals(fit_gdp)
parameter_hist(fit_gdp)
parameter_trace(fit_gdp)

# Ignoring minor factor influences
fit_reg <- minorbsem(syntax_1, HS, method = "none")
parameter_hist(fit_reg)
parameter_trace(fit_reg)

# Error!!!: Plotting residuals will give an error message
# since minor factor influences are assumed null
plot_residuals(fit_reg)

There are other methods, see details section in ?minorbsem.

Model comparison via LOO works as above in the first example.

Meta-analytic CFA

# An example in the metaSEM package, 11 studies, 9 items.
model_syntax <- "# latent variable definitions
F1 =~ JP1 + JP2 + JP3
F2 =~ JN1 + JN2 + JN4 + JN4
F3 =~ TD1 + TD2"
meta_fit <- meta_mbcfa(
  model_syntax,
  sample_cov = issp89$data, sample_nobs = issp89$n
)

# Histogram of parameters, see: ?parameter_hist for arguments
parameter_hist(meta_fit)

# Traceplot of parameters, see: ?parameter_trace for arguments
parameter_trace(meta_fit)

# Examine all standardized residual covariances
plot_residuals(meta_fit)
plot_residuals(meta_fit, type = "range")

There are other methods, see details section in ?meta_mbcfa.

Uanhoro (2022) addresses moderation (via meta-regression) and missing data in input covariances – these are not yet implemented.

Citations

MacCallum, Robert C., and Ledyard R. Tucker. 1991. “Representing Sources of Error in the Common-Factor Model: Implications for Theory and Practice.” Psychological Bulletin 109 (3): 502–11. https://doi.org/10.1037/0033-2909.109.3.502.
Uanhoro, James Ohisei. 2022. “Hierarchical Covariance Estimation Approach to Meta-Analytic Structural Equation Modeling.” Structural Equation Modeling: A Multidisciplinary Journal 0 (0): 1–15. https://doi.org/10.1080/10705511.2022.2142128.
———. 2023. “Modeling Misspecification as a Parameter in Bayesian Structural Equation Models.” Educational and Psychological Measurement 0 (0): 00131644231165306. https://doi.org/10.1177/00131644231165306.