Chapter 5 Testing for measurement invariance with lavaan in R
5.4 Data cleaning
Do whatever data wrangling necessary (missing values, etc)
Remember that you need a variable that identifies the group
5.5 Use lavaan language to formalize the model
The lavaan tutorial explains well how to formalize a theoretical model. It even includes a measurement invariance testing example.
In a nutshell:
Factor loadings in R are indicated by =∼ and covariances (between factors or error terms for items) are indicated by ∼∼. The model is specified similar to writing regression equations.
5.5.1 Example: Testing the Political Trust for measurement invariance
We want to know if we can compare the political trust concept in Portugal and Spain.
5.5.3 Model Building
Let´s build our model using lavaan model syntax
baseline <- 'political_trust =~ trstprl + trstlgl + trstplt + trstprt
'
#CFA function
fit_baseline<-cfa(baseline, data = mea_inv, group="cntry")
#Summary shows the estimation results
summary(fit_baseline, fit.measures=T, standardized = T)
## Length Class Mode
## 1 lavaan S4
5.5.4 Testing
Not a good model.
Commonly reported fit indices and recommended cut-offs
Measure | Name | Cut-off |
---|---|---|
CFI | Comparative Fit Index | CFI>=.90 |
RMSEA | Root Mean Square Root of Approximation | RMSEA<0.08 |
SRMR | Standardized Root Mean Square Residual | SRMR<0.08 |
Please take this as generally indicative. Read more about testing on Further Readings
5.5.5 Changing the original model
baseline1 <- 'political_trust =~ trstprl + trstlgl + trstplt + trstprt
trstplt ~~ trstprt
'
fit_configural<-cfa(baseline1, data = mea_inv, group="cntry")
summary(fit_configural, fit.measures=T, standardized = T)
## Length Class Mode
## 1 lavaan S4
Much better model. Configural Invariance set. Let’s go for metric.
5.5.6 Metric Invariance
metric <- 'political_trust =~ trstprl + trstlgl + trstplt + trstprt
trstplt ~~ trstprt
'
fit_metric<-cfa(baseline1, data = mea_inv, group="cntry", group.equal = c("loadings"))
summary(fit_metric, fit.measures=T, standardized = T)
## Length Class Mode
## 1 lavaan S4
Also a good model. Let’s go ahead for scalar.
5.5.7 Scalar Invariance
scalar <- 'political_trust =~ trstprl + trstlgl + trstplt + trstprt
trstplt ~~ trstprt
'
fit_scalar<-cfa(baseline1, data = mea_inv, group="cntry", group.equal = c("loadings", "intercepts"))
summary(fit_scalar, fit.measures=T, standardized = T)
## Length Class Mode
## 1 lavaan S4
Scalar Invariance holds!
5.5.8 Comparing several models using compareFit
## ################### Nested Model Comparison #########################
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
## fit_configural 2 25032 25174 6.9645
## fit_metric 5 25031 25157 11.6200 4.6555 3 0.19883
## fit_scalar 8 25031 25141 18.0521 6.4321 3 0.09238 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## ####################### Model Fit Indices ###########################
## chisq df pvalue cfi tli aic bic rmsea srmr
## fit_configural 6.965† 2 .031 0.998† .991 25032.320 25174.353 .053 .006†
## fit_metric 11.620 5 .040 0.998 .995 25030.976† 25156.620 .039 .018
## fit_scalar 18.052 8 .021 0.997 0.995† 25031.408 25140.664† .038† .020
##
## ################## Differences in Fit Indices #######################
## df cfi tli aic bic rmsea srmr
## fit_metric - fit_configural 3 -0.001 0.004 -1.345 -17.733 -0.014 0.012
## fit_scalar - fit_metric 3 -0.001 0.000 0.432 -15.956 -0.001 0.002
5.6 Omnibus invariance testing
##
## Measurement invariance models:
##
## Model 1 : fit.configural
## Model 2 : fit.loadings
## Model 3 : fit.intercepts
## Model 4 : fit.means
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
## fit.configural 2 25032 25174 6.9645
## fit.loadings 5 25031 25157 11.6200 4.6555 3 0.19883
## fit.intercepts 8 25031 25141 18.0521 6.4321 3 0.09238 .
## fit.means 9 25034 25138 22.3435 4.2914 1 0.03831 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
##
## Fit measures:
##
## cfi rmsea cfi.delta rmsea.delta
## fit.configural 0.998 0.053 NA NA
## fit.loadings 0.998 0.039 0.001 0.014
## fit.intercepts 0.997 0.038 0.001 0.001
## fit.means 0.996 0.041 0.001 0.003
Terry Jorgensen measurementInvariance function, within the semTools package is very handy