yrosseel / lavaan

an R package for structural equation modeling and more
http://lavaan.org
435 stars 99 forks source link

Order of groups in multiple-groups analysis #101

Closed aaronpeikert closed 6 years ago

aaronpeikert commented 6 years ago

Hello Yve, I am confused about how the order of groups is determent. It seems like, it is in the order in which the groups appear in the data. That don't make to much sense to me, because in most cases the order of rows is irrelevant. However instead I expected it to be according to the order of the levels of the factor of the group variable, or that it can be specified directly.

Example (also attached):

Setup

if(!require(pacman))install.packages(pacman)
pacman::p_load("tidyverse", "here", "lavaan")
set.seed(12345)

Simulation

Simulate some data with different groups.

n <- 200
sex_levels <- c("m", "w")
dfs <- rerun(2, tibble(X1 = rnorm(n), X2 = rnorm(n), resid1 = rnorm(n), resid2 = rnorm(n)))
names(dfs) <- sex_levels
dfs$m <- mutate(dfs$m,
           X1i1 = X1 + rnorm(n),
           X1i2 = X1 + rnorm(n),
           X1i3 = X1 + rnorm(n) + resid1,
           X1i4 = X1 + rnorm(n) + resid1,
           X2i1 = X2 + rnorm(n),
           X2i2 = X2 + rnorm(n),
           X2i3 = X2 + rnorm(n),
           X2i4 = X2 + rnorm(n))
dfs$m <- mutate_all(dfs$m, scale)
dfs$w <- mutate(dfs$w,
           X1i1 = X1 + rnorm(n),
           X1i2 = X1 + rnorm(n),
           X1i3 = X1 + rnorm(n),
           X1i4 = X1 + rnorm(n),
           X2i1 = X2 + rnorm(n),
           X2i2 = X2 + rnorm(n),
           X2i3 = X2 + rnorm(n) + resid2,
           X2i4 = X2 + rnorm(n) + resid2)
dfs$w <- mutate_all(dfs$w, scale)
dfs <- map2(dfs, c("m", "w"), ~mutate(.x, sex = .y))
df <- bind_rows(dfs)
df <- mutate(df, sex = as.factor(sex))
df <- select(df, -X1, -X2, -resid1, -resid2)
rm(dfs)

Generate Models

observed <- names(select(df, -sex))
gen_measure_model <- function(latent, observed){
  items <- grep(paste0("^", latent, collapse = ""), observed, value = TRUE)
  model <- paste0(latent, " =~ ", paste0(items, collapse = " + "))
  return(model)
}
model <- paste0(map_chr(c("X1", "X2"), gen_measure_model, observed), collapse = "\n")
cat(model)

Fit for all

fit <- cfa(model, df)
summary(fit, fit.measures = TRUE)
model_r <- paste(model, "X1i3 ~~ X1i4", "X2i3 ~~ X2i4", "\n", sep = " \n")
cat(model_r)
fit_r <- cfa(model_r, df)
summary(fit_r, fit.measures = TRUE)

Fit with groups

Variable unchanged

model_rg <- "X1 =~ X1i1 + X1i2 + X1i3 + X1i4
             X2 =~ X2i1 + X2i2 + X2i3 + X2i4
             X1i3 ~~ c(NA, 0)*X1i4
             X2i3 ~~ c(0, NA)*X2i4"

fit_rg1 <- cfa(model_rg, df, group = "sex")
#summary(fit_rg1)
fitMeasures(fit_rg1)

Varaible Factor reordered

df$sex <- relevel(df$sex, "w")
fit_rg2 <- cfa(model_rg, df, group = "sex")
#summary(fit_rg2)
fitMeasures(fit_rg2)

First Person different Group

df$sex[1] <- "w"
fit_rg3 <- cfa(model_rg, df, group = "sex")
#summary(fit_rg3)
fitMeasures(fit_rg3)
fabriciofialho commented 6 years ago

Hi, One can specify thenorder of groups using the “group.label” argument within lavaan()/cfa(). One can just add, for instance, “...group=“gender”, group.label=c(“female”,”male”)...” if you want ‘female’ to be the first group. Best,

aaronpeikert commented 6 years ago

Thank you! Sorry, but I now realized it was a RTFM case. As the documentation of lavaan() states

group.label: A character vector. The user can specify which group (or factor) levels need to be selected from the grouping variable, and in which order. If missing, all grouping levels are selected, in the order as they appear in the data.