R/InvarianceMatrices.R

Defines functions InvarianceMatrices

Documented in InvarianceMatrices

#' Invariance matrices
#'
#' \code{InvarianceMatrices} creates weak, strong, and strict invariance
#' matrices and returns them as a list. 
#'
#' This function takes tests each pair of groups for weak, strong, and strict
#' measurement invariance. The change in the CFI is calculated for each type of
#' measurement invariance, as recommended by Cheung & Rensovld (2002). 
#' 
#' Because each pair of groups is examined, computational load (and thus
#' runtime) can become high when there are many groups. For this reason, pairs 
#' of groups can be assessed in parallel with the \code{number.cores} argument.
#' 
#' @param data A data frame that contains the data for each group as well as 
#' a column that indicates the group of each row. The data should be organized
#' such that each indicator has 1 column with data from all groups,
#' @param group.variable A string indicating the name of the grouping column in
#' \code{data} 
#' @param lavaan.equations A string describing the structural equation model 
#' to examine measurement invariance (typically a confirmatory factor analysis 
#' model). This should be written in lavaan model syntax. See 
#' \code{\link[lavaan]{lavaan}} and 
#' \url{http://lavaan.ugent.be/tutorial/syntax1.html}. 
#' @param number.cores An integer specifying the number of (logical) cores to 
#' use. By default, only 1 core is used. Using all cores could slow down other 
#' programs running simultaneously. Thus, it is recommended to use 1 or 2 less
#' cores than the maximum possible. See \code{\link[parallel]{detectCores}}.
#' @return Thus function returns a list containing the weak, strong, and strict 
#' invariance matrices.
#'
#' @export
InvarianceMatrices <- function(data, group.variable, lavaan.equations, 
                               number.cores = 1L){
  # setting up parallel processing
  parallel.cluster <- parallel::makeCluster(number.cores)
  doParallel::registerDoParallel(parallel.cluster)
  # creating a matrix that contains all group pairs
  group.combinations <- t(combn(unique(data[, group.variable]), 2))
  # copying %dopar% so that it works
  '%dopar%' <- foreach::'%dopar%'
  # calculating delta CFIs for each pair of groups
  invariance.by.pair <- foreach::foreach(
    group.combinations.row = 1:nrow(group.combinations), 
    .combine = rbind, .inorder = T, .packages = "lavaan") %dopar% {
    # setting groups for this combination
    temp.group.1 <- group.combinations[group.combinations.row, 1]
    temp.group.2 <- group.combinations[group.combinations.row, 2]
    # subsetting data to just those groups
    temp.data <- data[grep(paste0(temp.group.1, "|", temp.group.2), 
                          data[, group.variable]), ]
    # running CFA models and extracting CFIs
    temp.configural.model <- lavaan::cfa(lavaan.equations, temp.data, 
                                 group = group.variable)
    temp.configural.cfi <- lavaan::fitMeasures(temp.configural.model, 
                                       fit.measures = "cfi")
    temp.weak.model <- lavaan::cfa(lavaan.equations, temp.data, 
                                   group = group.variable, 
                                   group.equal = "loadings")
    temp.weak.cfi <- lavaan::fitMeasures(temp.weak.model, fit.measures = "cfi")
    temp.strong.model <- lavaan::cfa(lavaan.equations, temp.data, 
                             group = group.variable, 
                             group.equal = c("loadings", "intercepts"))
    temp.strong.cfi <- lavaan::fitMeasures(temp.strong.model, 
                                           fit.measures = "cfi")
    temp.strict.model <- lavaan::cfa(lavaan.equations, temp.data, 
                             group = group.variable, 
                             group.equal = c("loadings", "intercepts", 
                                             "residuals"))
    temp.strict.cfi <- lavaan::fitMeasures(temp.strict.model, 
                                           fit.measures = "cfi")
    # calculating delta CFIs
    temp.weak.delta.cfi <- temp.configural.cfi - temp.weak.cfi
    temp.strong.delta.cfi <- temp.weak.cfi - temp.strong.cfi
    temp.strict.delta.cfi <- temp.strong.cfi - temp.strict.cfi
    temp.delta.cfi.matrix <- matrix(data = c(temp.weak.delta.cfi, 
                                             temp.strong.delta.cfi, 
                                             temp.strict.delta.cfi), 
                                    nrow = 1, ncol = 3)
    rownames(temp.delta.cfi.matrix) <- paste(temp.group.1, temp.group.2)
    colnames(temp.delta.cfi.matrix) <- c("weak.delta.cfi", "strong.delta.cfi", 
                                         "strict.delta.cfi")
    return(temp.delta.cfi.matrix)
  }
  # stopping parallel processing cluster
  parallel::stopCluster(parallel.cluster)
  # creating invariance matrices from delta CFIs for each pair of groups
  # creating matrix, naming rows and columns, then filling in matrix
  # weak
  weak.invariance.matrix <- matrix(
    nrow = length(unique(data[, group.variable])), 
    ncol = length(unique(data[, group.variable])))
  colnames(weak.invariance.matrix) <- rownames(weak.invariance.matrix) <- 
    unique(data[, group.variable])
  weak.invariance.matrix[lower.tri(weak.invariance.matrix)] <- 
    invariance.by.pair[, 1]
  weak.invariance.matrix <- t(weak.invariance.matrix)
  weak.invariance.matrix[lower.tri(weak.invariance.matrix)] <- 
    invariance.by.pair[, 1]
  # strong
  strong.invariance.matrix <- matrix(
    nrow = length(unique(data[, group.variable])),  
    ncol = length(unique(data[, group.variable])))
  colnames(strong.invariance.matrix) <- rownames(strong.invariance.matrix) <- 
    unique(data[, group.variable])
  strong.invariance.matrix[lower.tri(strong.invariance.matrix)] <- 
    invariance.by.pair[, 2]
  strong.invariance.matrix <- t(strong.invariance.matrix)
  strong.invariance.matrix[lower.tri(strong.invariance.matrix)] <- 
    invariance.by.pair[, 2]
  # strict
  strict.invariance.matrix <- matrix(
    nrow = length(unique(data[, group.variable])), 
    ncol = length(unique(data[, group.variable])))
  colnames(strict.invariance.matrix) <- rownames(strict.invariance.matrix) <- 
    unique(data[, group.variable])
  strict.invariance.matrix[lower.tri(strict.invariance.matrix)] <- 
    invariance.by.pair[, 3]
  strict.invariance.matrix <- t(strict.invariance.matrix)
  strict.invariance.matrix[lower.tri(strict.invariance.matrix)] <- 
    invariance.by.pair[, 3]
  #returning invariance matices
  return(list(weak.invariance.matrix = weak.invariance.matrix, 
              strong.invariance.matrix = strong.invariance.matrix,
              strict.invariance.matrix = strict.invariance.matrix))
}
sethmargolis/PairMeasInv documentation built on May 23, 2019, 1:48 p.m.