Nothing
#' Runs an EFA model based on items in a keys list.
#'
#' `efa.from.keys` runs a exploratory factor analysis (EFA) in lavaan with a
#' rotation targeted based on a keys list.
#'
#' @inheritParams sem.check
#' @param keys
#' A named list of keys. Names must be factor names, elements must be
#' vectors of items that should be targeted to load on the factor.
#' @param data
#' A dataframe or object coercible to a dataframe.
#' Data must include all observed variables in any of the keys.
#' @param name
#' A string indicating a subdirectory where model outputs will be saved when
#' `save_out = TRUE` and checked against when `check = TRUE`.
#' Defaults to 'efa'.
#' 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.
#' @param std.lv
#' Sets the `std.lv` param, as per lavaan (see [lavaan::lavOptions()]).
#' Defaults to `TRUE`.
#'
#' @return
#' Returns a list of lists.
#' The elements are a list of lavaan bifactor 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.
#'
#' @details
#' The function was designed to streamline running exploratory structural
#' equation models (ESEM) using Burt's (1976) 2-stage procedure to prevent
#' interpretational confounding in the context of ESEM. However, it can also be
#' used to easily run a targeted EFA with only a keys list to avoid having to
#' manually specify the target and model.
#'
#' The function was designed for use with established multidimensional scales,
#' such that a target is always reasonable.
#' The function does not currently support untargeted rotations.
#'
#' 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.
#'
#' @seealso
#' [sem.check()], which `efa.from.keys()` uses for all the back-end, and
#' [lavaan::sem()], which is used to estimate the models.
#'
#' @references
#' Burt, R. S. (1976).
#' Interpretational confounding of unobserved variables in Structural Equation
#' Models. Sociological Methods & Research, 5(1), 3-52.
#' https://doi.org/10.1177/004912417600500101.
#'
#' @importFrom lavaan summary
#' @export
#'
#' @examples
#' # Create EFA keys
#' # Using only 3 factors to save time
#' keys_e0 <- paste0("bfi_", c("e", "a", "c"))
#' # Using less than all items to save time
#' # (This results in a less than ideal solution but it shouldn't matter for an
#' # example)
#' keys_e <- sapply(
#' keys_e0,
#' function(x) {
#' names(BFIGritHope)[grep(paste0(x, "\\d_[1-2]"), names(BFIGritHope))]
#' },
#' simplify = FALSE
#' )
#' # Run model
#' efa_fit <- efa.from.keys(keys_e, BFIGritHope, check = FALSE, fit_save = TRUE)
#' # Examine results
#' summary(efa_fit$fit$efa) # Standard lavaan summary
#' efa_fit$fit_measures[, c("cfi", "rmsea")] # Fit measures
efa.from.keys <- function(
keys, data, orthogonal = FALSE, fit_save = TRUE, fit_measures = "all",
std.lv = TRUE, miss = "ML", est = "default",
name = "efa", check = FALSE, save_out = FALSE
) {
target <- sapply(keys, function(y) ifelse(!unlist(keys) %in% y, 0, NA))
mod <- list(
paste(
paste0(
paste0('efa("', name, '")*', names(keys), collapse = " + "),
" =~\n",
paste(unlist(keys), collapse = " + ")
)
)
)
names(mod) <- name
sem.check(
mod,
data,
name = name,
keys_s = NULL,
keys_e = keys,
std = FALSE, # For use in 2-stage procedure, must use non-standardised.
fit_save = fit_save,
fit_measures = fit_measures,
orthogonal = orthogonal,
std.lv = std.lv,
target = target,
miss = miss,
est = est,
check = check,
save_out = save_out
)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.