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.2 Load lavaan and semTools
library(lavaan)
library(semTools)
5.5.3 Model Building
Let´s build our model using lavaan model syntax
'political_trust =~ trstprl + trstlgl + trstplt + trstprt
baseline <-'
#CFA function
cfa(baseline, data = mea_inv, group="cntry")
fit_baseline<-
#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
'political_trust =~ trstprl + trstlgl + trstplt + trstprt
baseline1 <-trstplt ~~ trstprt
'
cfa(baseline1, data = mea_inv, group="cntry")
fit_configural<-
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
'political_trust =~ trstprl + trstlgl + trstplt + trstprt
metric <-trstplt ~~ trstprt
'
cfa(baseline1, data = mea_inv, group="cntry", group.equal = c("loadings"))
fit_metric<-
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
'political_trust =~ trstprl + trstlgl + trstplt + trstprt
scalar <-trstplt ~~ trstprt
'
cfa(baseline1, data = mea_inv, group="cntry", group.equal = c("loadings", "intercepts"))
fit_scalar<-
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
compareFit(fit_configural, fit_metric, fit_scalar)
## ################### 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
measurementInvariance (model = baseline1, data = mea_inv, group = "cntry")
##
## 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
5.7 Advanced Tutorial: Partial Invariance (individually constraining parameters)

Figure 5.1: Source: Designed by starline / Freepik