I am currently learning how to implement CFA and invariance of constructs between two groups. My data below has two groups. So my steps are as follows

  • Confirm the overall model works
  • Check if both groups have a high enough CFIto perform invariance testing
  • Perform invariance testing (Configural, Metric, Scalar etc)

I originally created a CFA on a model and got a CFI of 0.9305597. When I attempted to implement invariance testing the configural step gave me a CFI of 0.9233984

model.between.groups <- measurementInvariance(model=HS.model, data = mydf, group="school", strict = TRUE)

For the configural step I got a value of 0.90 for the CFI

My understanding of the the configural step is that it just combines the groups together with no restrictions on the model. Should the CFI not be the same as a result?

Below is a reproducible example which you should be able to run if the lavaan library is installed (I apologize for the spaghetti code) The table fit_df contains the fit statistics

Any help would be greatly appreciated



mydf <- HolzingerSwineford1939

# First Create the CFA model for both groups combined
HS.model <- ' visual  =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed   =~ x7 + x8 + x9'

# Fitting the model with both groups together
all.fit <- cfa(HS.model, data=HolzingerSwineford1939)
summary(all.fit, standardized= TRUE, rsquare = TRUE)

# Create Fit Indices
fit.indices <- c('chisq','df','cfi','tli','srmr','rmsea','rmsea.ci.lower','rmsea.ci.upper')
fit_df <- as.data.frame(fitmeasures(object = all.fit, fit.indices))
names(fit_df) <- 'CFA_Model'

# Split by Group to check that CFI is high enough for both groups to do invariant testing
construct.pasteur <- filter(mydf, school == 'Pasteur')
construct.gw <- filter(mydf, school == 'Grant-White')

pasteur.fit <- cfa(HS.model, data = construct.pasteur, meanstructure = TRUE)
gw.fit <- cfa(HS.model, data = construct.gw, meanstructure = TRUE)

# Specify the fit statistics
fit_df <- fit_df %>%
  cbind (as.data.frame(fitmeasures(object = pasteur.fit, fit.indices))) %>%
  cbind (as.data.frame(fitmeasures(object = gw.fit, fit.indices)))

names(fit_df) <- c('CFA_Model','pasteur.fit','gw.fit')

# Model Invariance to see if its possible to use the questionaire across groups
model.between.groups <- measurementInvariance(model=HS.model, data = mydf,  group="school", strict = TRUE)

# Add the model statistics to the summary Table
fit_df <-  fit_df %>%
  cbind(as.data.frame(fitmeasures(object = model.between.groups$fit.configural, fit.indices))) %>%
  cbind(as.data.frame(fitmeasures(object = model.between.groups$fit.loadings, fit.indices))) %>%
  cbind(as.data.frame(fitmeasures(object = model.between.groups$fit.intercepts, fit.indices))) %>%
  cbind(as.data.frame(fitmeasures(object = model.between.groups$fit.residuals, fit.indices)))      

names(fit_df) <-  c('CFA_Model','pasteur.fit','gw.fit','configural','loadings','intercepts','residuals')


Why do you assume that the configural step should get the same CFI result as the model with no grouping? They are not the same. The latter estimates simply one parameter and ignores any grouping while the former lets them vary by group. So naturally, you'll get somewhat different results.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.