Item Factor Analysis, Measurement Invariance + 2nd order Growth Model (ECLS-K)
Nilam Ram, Kevin Grimm et al.
1 Overview
In this tutorial we walk through example of testing measurement invariance and modeling change with latent variables measured by Ordinal indicators.
The example follows Chapter 15 of Growth Modeling: Structural Equation and Multilevel Modeling Approaches (Grimm, Ram & Estabrook, 2017).
Using 3-occasion data from the ECLS-K, we set up an item factor analysis model, test for factorial invariance, and then use a second-order growth model to describe change in the factor scores across time.
1.0.0.1 Prelim - Loading libraries used in this script.
library(psych)
library(ggplot2)
library(corrplot) #plotting correlation matrices
library(lavaan) #for fitting structural equation models
library(semPlot) #for automatically making diagrams
1.0.0.2 Prelim - Reading in Repeated Measures Data
For this example, we use an ECLS-K dataset that is in wideform. There are variables for parent’s and teachers’ ratings of children’s of children’s behavior in the fall and spring of kindergarten and spring of first grade on interpersonal skills, self-control, and externalizing behaviors. Ratings were made using a four-point (1-4) scale where higher values indicated more of the behavior.
These behavior ratings are thought to be indicators of a higher-order child behavior factor
We only use the teacher ratings here.
#set filepath for data file
<- "https://raw.githubusercontent.com/LRI-2/Data/main/GrowthModeling/ECLS_Behavior.dat"
filepath #read in the text data file using the url() function
<- read.table(file=url(filepath),na.strings = ".")
dat
names(dat) <- c("id",
"p1_sc", "p1_soc", "p1_sad", "p1_imp",
"p2_sc", "p2_soc", "p2_sad", "p2_imp",
"p4_sc", "p4_soc", "p4_sad", "p4_imp",
"t1_sc", "t1_intp", "t1_ext", "t1_int",
"t2_sc", "t2_intp", "t2_ext", "t2_int",
"t4_sc", "t4_intp", "t4_ext", "t4_int")
#selecting only the teacher reports
<- dat[ ,c("id", "t1_sc", "t1_intp", "t1_ext", "t1_int",
dat "t2_sc", "t2_intp", "t2_ext", "t2_int",
"t4_sc", "t4_intp", "t4_ext", "t4_int")]
1.0.0.3 Prelim - Descriptives
Lets have a quick look at the data file and the descriptives.
#look at data structure
head(dat,10)
id | t1_sc | t1_intp | t1_ext | t1_int | t2_sc | t2_intp | t2_ext | t2_int | t4_sc | t4_intp | t4_ext | t4_int |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 4 | 4 | 1 | 2 | NA | NA | NA | NA | 4 | 3 | 1 | 1 |
2 | 4 | 4 | 1 | 1 | 4 | 4 | 1 | 1 | 4 | 4 | 1 | 1 |
16 | 3 | 2 | 2 | 1 | 4 | 4 | 1 | 1 | 3 | 4 | 1 | 2 |
19 | 4 | 4 | 1 | 1 | 4 | 4 | 1 | 1 | 3 | 3 | 1 | 3 |
35 | 4 | 3 | 1 | 2 | 3 | 3 | 1 | 3 | 3 | 2 | 1 | 2 |
36 | 3 | 3 | 2 | 1 | 3 | 3 | 2 | 2 | 3 | 3 | 2 | 2 |
48 | 4 | 3 | 1 | 2 | 4 | 4 | 1 | 2 | 4 | 3 | 1 | 1 |
50 | 4 | 2 | 1 | 2 | 2 | 3 | 2 | 3 | 4 | 3 | 1 | 2 |
54 | 3 | 3 | 2 | 3 | 3 | 2 | 2 | 3 | 3 | 2 | 3 | 2 |
58 | 3 | NA | 3 | 2 | 3 | 2 | 4 | 3 | 3 | 3 | 3 | 2 |
#descriptives (means, sds)
describe(dat[,-1]) #-1 to remove the id column
vars | n | mean | sd | median | trimmed | mad | min | max | range | skew | kurtosis | se | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
t1_sc | 1 | 3198 | 3.215135 | 0.6949452 | 3 | 3.273828 | 1.4826 | 1 | 4 | 3 | -0.3897593 | -0.6238324 | 0.0122889 |
t1_intp | 2 | 3162 | 3.024668 | 0.7159051 | 3 | 3.040712 | 0.0000 | 1 | 4 | 3 | -0.1654381 | -0.6702866 | 0.0127314 |
t1_ext | 3 | 3262 | 1.586143 | 0.6981145 | 1 | 1.476628 | 0.0000 | 1 | 4 | 3 | 1.0780229 | 0.9799469 | 0.0122232 |
t1_int | 4 | 3231 | 1.545342 | 0.6273211 | 1 | 1.475048 | 0.0000 | 1 | 4 | 3 | 0.8931608 | 0.6133514 | 0.0110362 |
t2_sc | 5 | 3479 | 3.307560 | 0.7001419 | 3 | 3.389228 | 1.4826 | 1 | 4 | 3 | -0.5764546 | -0.5477944 | 0.0118702 |
t2_intp | 6 | 3460 | 3.191330 | 0.7131807 | 3 | 3.244220 | 1.4826 | 1 | 4 | 3 | -0.3633800 | -0.7522430 | 0.0121244 |
t2_ext | 7 | 3482 | 1.646467 | 0.7069649 | 2 | 1.536253 | 1.4826 | 1 | 4 | 3 | 0.9315256 | 0.6705202 | 0.0119807 |
t2_int | 8 | 3466 | 1.587998 | 0.6323781 | 2 | 1.520908 | 1.4826 | 1 | 4 | 3 | 0.7793179 | 0.4288969 | 0.0107414 |
t4_sc | 9 | 3619 | 3.284885 | 0.6969259 | 3 | 3.359337 | 1.4826 | 1 | 4 | 3 | -0.5016578 | -0.6670892 | 0.0115849 |
t4_intp | 10 | 3610 | 3.125208 | 0.7246991 | 3 | 3.163435 | 1.4826 | 1 | 4 | 3 | -0.2816960 | -0.7838474 | 0.0120616 |
t4_ext | 11 | 3621 | 1.631593 | 0.7122732 | 2 | 1.517777 | 1.4826 | 1 | 4 | 3 | 0.9590041 | 0.6168455 | 0.0118367 |
t4_int | 12 | 3639 | 1.636988 | 0.6445657 | 2 | 1.567800 | 1.4826 | 1 | 4 | 3 | 0.7215088 | 0.4414765 | 0.0106850 |
#correlation matrix
round(cor(dat[,-1], use = "pairwise.complete"),2)
## t1_sc t1_intp t1_ext t1_int t2_sc t2_intp t2_ext t2_int t4_sc t4_intp
## t1_sc 1.00 0.69 -0.59 -0.25 0.55 0.48 -0.48 -0.18 0.34 0.33
## t1_intp 0.69 1.00 -0.48 -0.31 0.47 0.53 -0.39 -0.23 0.29 0.32
## t1_ext -0.59 -0.48 1.00 0.20 -0.51 -0.45 0.64 0.14 -0.38 -0.34
## t1_int -0.25 -0.31 0.20 1.00 -0.18 -0.23 0.15 0.47 -0.10 -0.15
## t2_sc 0.55 0.47 -0.51 -0.18 1.00 0.70 -0.63 -0.26 0.39 0.36
## t2_intp 0.48 0.53 -0.45 -0.23 0.70 1.00 -0.54 -0.31 0.34 0.36
## t2_ext -0.48 -0.39 0.64 0.15 -0.63 -0.54 1.00 0.24 -0.41 -0.36
## t2_int -0.18 -0.23 0.14 0.47 -0.26 -0.31 0.24 1.00 -0.13 -0.16
## t4_sc 0.34 0.29 -0.38 -0.10 0.39 0.34 -0.41 -0.13 1.00 0.72
## t4_intp 0.33 0.32 -0.34 -0.15 0.36 0.36 -0.36 -0.16 0.72 1.00
## t4_ext -0.37 -0.30 0.46 0.09 -0.41 -0.36 0.49 0.11 -0.62 -0.55
## t4_int -0.15 -0.16 0.12 0.20 -0.14 -0.16 0.13 0.24 -0.28 -0.32
## t4_ext t4_int
## t1_sc -0.37 -0.15
## t1_intp -0.30 -0.16
## t1_ext 0.46 0.12
## t1_int 0.09 0.20
## t2_sc -0.41 -0.14
## t2_intp -0.36 -0.16
## t2_ext 0.49 0.13
## t2_int 0.11 0.24
## t4_sc -0.62 -0.28
## t4_intp -0.55 -0.32
## t4_ext 1.00 0.29
## t4_int 0.29 1.00
#visusal correlation matrix
corrplot(cor(dat[,-1], use = "pairwise.complete"), order = "original", tl.col='black', tl.cex=.75)