Chapter 16 – Latent Change Score Modeling

1 Overview

This tutorial walks through the fitting of univariate latent change score models in the structural equation modeling framework in R using using the lavaan package.

The example follows Chapter 16 of Grimm, Ram, and Estabrook (2017). Please refer to the chapter for further interpretations and insights about the analyses.

1.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.2 Prelim - Reading in Repeated Measures Data

We use data from the NLSY-CYA (Center for Human Resource Research, 2009) that includes repeated measures of children’s math ability (math) from the second through eighth grade.

Reading in the data

#set filepath
filepath <- "https://raw.githubusercontent.com/LRI-2/Data/main/GrowthModeling/nlsy_math_wide_R.dat"
#read in the text data file using the url() function
nlsy_data <- read.table(file=url(filepath),na.strings = ".")

#adding names for the columns of the data set
names(nlsy_data) <- c('id', 'female', 'lb_wght', 'anti_k1', 'math2', 'math3', 'math4', 'math5', 'math6', 'math7', 'math8', 'age2', 'age3', 'age4', 'age5', 'age6', 'age7', 'age8', 'men2', 'men3', 'men4', 'men5', 'men6', 'men7', 'men8', 'spring2', 'spring3', 'spring4', 'spring5', 'spring6', 'spring7', 'spring8', 'anti2', 'anti3', 'anti4', 'anti5', 'anti6', 'anti7', 'anti8')

#reduce data down to the id variable and the math and reading variables of interest
nlsy_data <- nlsy_data[ ,c('id', 'math2', 'math3', 'math4', 'math5', 'math6', 'math7', 'math8')]

psych::describe(nlsy_data)
vars n mean sd median trimmed mad min max range skew kurtosis se
id 1 933 532334.89711 3.280208e+05 506602.0 520130.77108 391999.4400 201 1256601 1256400 0.2841659 -0.9078872 1.073892e+04
math2 2 335 32.60896 1.028600e+01 32.0 32.27509 10.3782 12 60 48 0.2686681 -0.4600130 5.619840e-01
math3 3 431 39.88399 1.029949e+01 41.0 39.88406 10.3782 13 67 54 -0.0520929 -0.3259168 4.961091e-01
math4 4 378 46.16931 1.016510e+01 46.0 46.22039 8.8956 18 70 52 -0.0595783 -0.0759665 5.228366e-01
math5 5 372 49.77419 9.471909e+00 48.0 49.76510 8.8956 23 71 48 0.0425474 -0.3381126 4.910956e-01
math6 6 390 52.72308 9.915594e+00 50.5 52.38462 9.6369 24 78 54 0.2510417 -0.3808615 5.020956e-01
math7 7 173 55.35260 1.062727e+01 53.0 55.08633 11.8608 31 81 50 0.2148479 -0.9709622 8.079765e-01
math8 8 142 57.83099 1.153101e+01 56.0 57.42982 12.6021 26 81 55 0.1590545 -0.5222967 9.676607e-01

1.0.3 Prelim - Plotting the Repeated Measures Data

#reshaping wide to wide
data_long <- reshape(data=nlsy_data,
                    varying = c('math2', 'math3', 'math4', 'math5', 'math6', 'math7', 'math8'),
                    timevar=c("grade"), 
                    idvar=c("id"),
                    direction="long", sep="")

#sorting for easy viewing
#reorder by id and day
data_long <- data_long[order(data_long$id,data_long$grade), ]

#looking at the long data
head(data_long, 8)
id grade math
201.2 201 2 NA
201.3 201 3 38
201.4 201 4 NA
201.5 201 5 55
201.6 201 6 NA
201.7 201 7 NA
201.8 201 8 NA
303.2 303 2 26
#Plotting intraindividual change MATH
ggplot(data = data_long, aes(x = grade, y = math, group = id)) +
  geom_point(color="blue") + 
  geom_line(color="blue") +
  xlab("Grade") + 
  ylab("PIAT Mathematics") + 
  scale_x_continuous(limits=c(2,8), breaks=seq(2,8,by=1)) +
  scale_y_continuous(limits=c(0,90), breaks=seq(0,90,by=10))
## Warning: Removed 4310 rows containing missing values (geom_point).
## Warning: Removed 2787 row(s) containing missing values (geom_path).