bifactor.from.keys: Runs bifactor models for multiple scales based on keys lists.

View source: R/bifactor.from.keys.R

bifactor.from.keysR Documentation

Runs bifactor models for multiple scales based on keys lists.

Description

bifactor.from.keys runs a series of bifactor model from three keys lists— one for items on general factor; one for items on group factors; and one for group factors on general factors. The keys list must be named appropriately (i.e., general factor names, group factor names, and general factor names for the three lists respectively). The function is designed to streamline running measurement models for all scales in a sample and to input model outputs into downstream functions.

Usage

bifactor.from.keys(
  keys_g,
  keys_b,
  keys,
  data,
  fit_save = TRUE,
  fit_measures = "all",
  std.lv = TRUE,
  miss = "ML",
  est = "default",
  name = "bifactor",
  check = FALSE,
  save_out = FALSE
)

Arguments

keys_g

A named list of items in general factors. Names must be the names of the general factors. Each list element must be a vector of items that load on the general factors. Must be the same length as keys_b.

keys_b

A named list of group factors in general factors. Names must be the names of the general factors. Each list element must be a vector of group factors that load on the general factors. Must be the same length as keys_g.

keys

A named list of items in group factors. Names must be the names of the group factors. Each list element must be a vector of items that load on the group factors. Need not be the same length as keys_g and keys_b.

data

A dataframe or object coercible to a dataframe. Data must include all observed variables in any of the keys.

fit_save

Logical. TRUE indicates model fit measures should be included in the output; FALSE indicates model fit measures should not be included in the output. FALSE may be desirable when fit measures are of little interest and when they may take a long time to estimate. Fit can still be examined for individual models with, ⁠lavaan::fitMeasures(fit$fit$[model name])⁠.

fit_measures

A vector of fit measures to save or 'all' to select all fit measures, as per the fit.measures parameter from lavaan's lavaan::fitMeasures() function. Defaults to 'all'. Irrelevant if fit_save = FALSE.

std.lv

Logical. Sets the std.lv parameter, as per lavaan (see lavaan::lavOptions()). TRUE indicates that factor variances should be fixed to 1. FALSE indicates that loadings of the first items of factors should be fixed to 1. Defaults to TRUE.

miss

A string. Sets the missing parameter, as per lavaan (see lavaan::lavOptions()). Defaults to 'ML'.

est

A string. Sets the estimator parameter, as per lavaan (see lavaan::lavOptions()). The default ('default') uses the lavaan default for the model being run.

name

A string indicating a subdirectory where model outputs will be saved when save_out = TRUE and checked against when check = TRUE. Defaults to 'bifactor'. Irrelevant if both save_out = FALSE and check = FALSE. The name should be unique for each set of models or outputs from calls with the same name will be overwritten.

check

Logical. TRUE indicates that current inputs should be compared to previous inputs if they exist and that the model should not be rerun if nothing has changed; FALSE indicates that these checks should not be made and the model should be run regardless of the existence of previous inputs.

save_out

Logical. TRUE indicates that model code, a hash of the data, important input parameter values, and output will be saved; FALSE indicates that nothing will be saved. Selecting save_out = TRUE enables the function to not rerun models next time if check = TRUE the next time the code is run and nothing has changed in the meantime.

Details

The model relies on sem.check() for the back-end of running the models. This enables saving inputs and outputs from model runs (with save_out = TRUE) and checking to see if anything has changed from prior runs before running again (with check = TRUE). The functionality was included for a number of very slow models or a lot of faster models, such that time spent rerunning them would be onerous. For further details on how this works, see the sem.check() function documentation.

Please be careful with bifactor models. In simulation studies, they can fit better than the models that generated the data in the presence of unspecified complexity (which is usually the case; Murray & Johnson, 2013). They can also produce negative residual variances. lavaan will warn you of this and you should deal with it before proceeding. Items can also load in atheoretical ways on the general or group factors. This could be some items loading negatively instead of positively or vice versa or one or more items having insignificant loadings on a factor that they should theoretically load on.

These problems can often be solved by omitting a factor. When items from one group factor dominate the general factor, the best solution might be to remove the general factor and treat the group factors as separate constructs. Perhaps more frequently, these problems might be solved by omitting one (or more) group factors (i.e., an S-1 model; Eid et al., 2017). This can either be done a priori (perhaps based on which one should theoretically be most 'central' to the general factor) or after examining the fully specified bifactor model and dropping the worst performing factor (see the example). When more than one group factor is poor, I am not aware of any specific advice on which to remove, so use your judgment if previous research has not got any advice for your case.

Value

Returns a list of length 2 (if fit_save = FALSE) or 3 (if fit_save = TRUE). The elements of the list are: a list of lavaan model output objects; a list of parameter estimates from the models (standardized if std = TRUE); and, if fit_save = TRUE, a matrix of fit measures for each model.

References

Eid, M., Geiser, C., Koch, T., & Heene, M. (2017). Anomalous results in G-factor models: Explanations and alternatives. Psychological Methods, 22(3), 541-562. https://doi.org/10.1037/met0000083.

Murray, A. L. & Johnson, W. (2013). The limitations of model fit in comparing the bi-factor versus higher-order models of human cognitive ability structure. Intelligence, 41(5), 407-422. https://doi.org/10.1016/j.intell.2013.06.004.

See Also

sem.check(), which bifactor.from.keys() uses for all the back-end, and lavaan::sem(), which is used to estimate the models.

Examples

# Create keys
keys0 <- c("grit_c", "grit_p", "hope_a", "hope_p")
keys <- sapply(
  keys0, function(x) names(BFIGritHope)[grep(x, names(BFIGritHope))]
)
keys_g0 <- c("grit", "hope")
keys_g <- sapply(
  keys_g0, function(x) names(BFIGritHope)[grep(x, names(BFIGritHope))]
)
keys_b1 <- sapply(
  keys_g0, function(x) keys0[grep(x, keys0)], simplify = FALSE
)
# Including all factors produces a negative residual variance for hope.
bif_fit0 <- bifactor.from.keys(
  keys_g, keys_b1, keys, BFIGritHope, check = FALSE, fit_save = TRUE
)
summary(bif_fit0$fit$hope)
# Fix negative residual variance by removing the first group factor.
keys_b <- keys_b1
keys_b$hope <- keys_b1$hope[-1]
bif_fit <- bifactor.from.keys(
  keys_g, keys_b, keys, BFIGritHope, check = FALSE, fit_save = TRUE
)
# Examine some results
summary(bif_fit$fit$grit)                  # Standard lavaan summary
bif_fit$fit_measures[, c("cfi", "rmsea")]  # Fit measures

semFromKeys documentation built on July 24, 2026, 5:07 p.m.