Overview

Along the same purpose with tutorials of previous chapters. This tutorial walks through the fitting of latent change score model (dual change model) in the structural equation framework. In this tutorial, we will be using a sample data set that includes repeated measures of individuals’ mathematics achievement through elementary and middle school (dataset named as nlsy_math_wide_R.dat in the original dataset accompanying the book, and here we converted to a csv file, see link on the left).

The data, code and example provided in this tutorial are adapted from Chapter 16 of Grimm, Ram, and Estabrook (2016), with a few additions in code and commentary. Please refer to the chapter for further interpretations and insights about the analyses.

Outline

This tutorial provides line-by-line code to

1. Fit a dual change model in lavaan (for diagram see Figure 16.2 on page 410)

Step 0: Read in the data and call needed libraries

Prepare data in “long” format.

library(nlme)
require(lavaan)
require(dplyr)
require(tidyr)

For this tutorial, we will access the relevant data through the QuantDev website by first setting the file path to the data file, and then using the read.csv() to load these data into R.

# Set filepath
filepath_wide <- "https://quantdev.ssri.psu.edu/sites/qdev/files/nlsy_math_wide.csv"
# Read in the .csv file using the url() function
summary(nlsy_math_wide)
##        id              female         lb_wght           anti_k1
##  Min.   :    201   Min.   :0.000   Min.   :0.00000   Min.   :0.000
##  1st Qu.: 261503   1st Qu.:0.000   1st Qu.:0.00000   1st Qu.:0.000
##  Median : 506602   Median :0.000   Median :0.00000   Median :1.000
##  Mean   : 532335   Mean   :0.492   Mean   :0.08039   Mean   :1.454
##  3rd Qu.: 794503   3rd Qu.:1.000   3rd Qu.:0.00000   3rd Qu.:2.000
##  Max.   :1256601   Max.   :1.000   Max.   :1.00000   Max.   :8.000
##
##      math2           math3           math4           math5
##  Min.   :12.00   Min.   :13.00   Min.   :18.00   Min.   :23.00
##  1st Qu.:25.00   1st Qu.:32.00   1st Qu.:40.00   1st Qu.:44.00
##  Median :32.00   Median :41.00   Median :46.00   Median :48.00
##  Mean   :32.61   Mean   :39.88   Mean   :46.17   Mean   :49.77
##  3rd Qu.:40.00   3rd Qu.:47.00   3rd Qu.:52.00   3rd Qu.:57.00
##  Max.   :60.00   Max.   :67.00   Max.   :70.00   Max.   :71.00
##  NA's   :598     NA's   :502     NA's   :555     NA's   :561
##      math6           math7           math8            age2
##  Min.   :24.00   Min.   :31.00   Min.   :26.00   Min.   : 82.00
##  1st Qu.:46.00   1st Qu.:47.00   1st Qu.:49.00   1st Qu.: 93.00
##  Median :50.50   Median :53.00   Median :56.00   Median : 97.00
##  Mean   :52.72   Mean   :55.35   Mean   :57.83   Mean   : 97.22
##  3rd Qu.:61.00   3rd Qu.:63.00   3rd Qu.:66.00   3rd Qu.:101.00
##  Max.   :78.00   Max.   :81.00   Max.   :81.00   Max.   :121.00
##  NA's   :543     NA's   :760     NA's   :791     NA's   :598
##       age3            age4            age5          age6
##  Min.   : 92.0   Min.   :105.0   Min.   :115   Min.   :127.0
##  1st Qu.:104.0   1st Qu.:116.0   1st Qu.:129   1st Qu.:140.0
##  Median :108.0   Median :120.5   Median :133   Median :144.0
##  Mean   :108.6   Mean   :120.8   Mean   :133   Mean   :144.8
##  3rd Qu.:113.0   3rd Qu.:125.0   3rd Qu.:137   3rd Qu.:150.0
##  Max.   :133.0   Max.   :151.0   Max.   :155   Max.   :170.0
##  NA's   :502     NA's   :555     NA's   :561   NA's   :543
##       age7            age8            men2          men3
##  Min.   :140.0   Min.   :155.0   Min.   :0     Min.   :0.0000
##  1st Qu.:154.0   1st Qu.:163.2   1st Qu.:0     1st Qu.:0.0000
##  Median :157.0   Median :167.0   Median :0     Median :0.0000
##  Mean   :157.4   Mean   :166.6   Mean   :0     Mean   :0.0043
##  3rd Qu.:161.0   3rd Qu.:170.0   3rd Qu.:0     3rd Qu.:0.0000
##  Max.   :173.0   Max.   :175.0   Max.   :0     Max.   :1.0000
##  NA's   :760     NA's   :791     NA's   :781   NA's   :699
##       men4             men5             men6             men7
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000
##  1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000
##  Median :0.0000   Median :0.0000   Median :0.0000   Median :1.0000
##  Mean   :0.0417   Mean   :0.1129   Mean   :0.3081   Mean   :0.7308
##  3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:1.0000
##  Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000
##  NA's   :765      NA's   :747      NA's   :748      NA's   :855
##       men8           spring2         spring3          spring4
##  Min.   :0.0000   Min.   :0.000   Min.   :0.0000   Min.   :0.0000
##  1st Qu.:1.0000   1st Qu.:0.000   1st Qu.:0.0000   1st Qu.:0.0000
##  Median :1.0000   Median :1.000   Median :1.0000   Median :1.0000
##  Mean   :0.9296   Mean   :0.609   Mean   :0.5452   Mean   :0.6455
##  3rd Qu.:1.0000   3rd Qu.:1.000   3rd Qu.:1.0000   3rd Qu.:1.0000
##  Max.   :1.0000   Max.   :1.000   Max.   :1.0000   Max.   :1.0000
##  NA's   :862      NA's   :598     NA's   :502      NA's   :555
##     spring5          spring6          spring7          spring8
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000
##  1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:1.0000   1st Qu.:0.0000
##  Median :1.0000   Median :1.0000   Median :1.0000   Median :1.0000
##  Mean   :0.6613   Mean   :0.7077   Mean   :0.7861   Mean   :0.7183
##  3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.0000
##  Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000
##  NA's   :561      NA's   :543      NA's   :760      NA's   :791
##      anti2           anti3           anti4           anti5
##  Min.   :0.000   Min.   :0.000   Min.   :0.000   Min.   :0.000
##  1st Qu.:0.000   1st Qu.:0.000   1st Qu.:0.000   1st Qu.:0.000
##  Median :1.000   Median :1.000   Median :1.000   Median :1.000
##  Mean   :1.482   Mean   :1.544   Mean   :1.535   Mean   :1.572
##  3rd Qu.:2.000   3rd Qu.:2.000   3rd Qu.:2.000   3rd Qu.:3.000
##  Max.   :8.000   Max.   :8.000   Max.   :7.000   Max.   :8.000
##  NA's   :603     NA's   :512     NA's   :563     NA's   :571
##      anti6           anti7           anti8
##  Min.   :0.000   Min.   :0.000   Min.   :0.000
##  1st Qu.:0.000   1st Qu.:1.000   1st Qu.:0.000
##  Median :1.000   Median :1.000   Median :1.000
##  Mean   :1.693   Mean   :1.681   Mean   :1.586
##  3rd Qu.:3.000   3rd Qu.:3.000   3rd Qu.:2.250
##  Max.   :8.000   Max.   :7.000   Max.   :8.000
##  NA's   :555     NA's   :764     NA's   :793

Step 1. Run latent change score model within the SEM framework, using R package lavaan.

(Friendly reminder) For lavaan, data needs to be in wide format.

model.syntax <- "

# latent variables are indicated by the observed variables (also considered factor loadings)
ly1 =~ 1* math2 # ly1 is indicated by math2, factor loading = 1
ly2 =~ 1* math3
ly3 =~ 1* math4
ly4 =~ 1* math5
ly5 =~ 1* math6
ly6 =~ 1* math7
ly7 =~ 1* math8

dy2 =~ 1 * ly2 # dy2 is indicated by ly2, factor loading = 1
dy3 =~ 1 * ly3
dy4 =~ 1 * ly4
dy5 =~ 1 * ly5
dy6 =~ 1 * ly6
dy7 =~ 1 * ly7

# the constant change, g2, is indicated by dy2~dy7
g2 =~ 1*dy2 + 1*dy3 + 1*dy4 + 1*dy5 + 1*dy6 + 1*dy7

# factor means
ly1 ~ 1
g2 ~ 1

# regressions
ly2 ~ 1 * ly1 + 1 * dy2 # ly2 is regressed on ly1 and dy2, regression coefficient is fixed at 1
ly3 ~ 1 * ly2 + 1 * dy3
ly4 ~ 1 * ly3 + 1 * dy4
ly5 ~ 1 * ly4 + 1 * dy5
ly6 ~ 1 * ly5 + 1 * dy6
ly7 ~ 1 * ly6 + 1 * dy7

# autoproportions, the changes of dy2 to dy7 is also proportional to ly1 to ly6, respectively
dy2 ~ pi * ly1 # dy2 is regressed on ly1, the regression coefficient is estimated as pi
dy3 ~ pi * ly2
dy4 ~ pi * ly3
dy5 ~ pi * ly4
dy6 ~ pi * ly5
dy7 ~ pi * ly6

# covariances among factors
ly1 ~~ ly1
g2 ~~ g2
ly1 ~~ g2

ly2 ~~ 0*ly2
ly3 ~~ 0*ly3
ly4 ~~ 0*ly4
ly5 ~~ 0*ly5
ly6 ~~ 0*ly6
ly7 ~~ 0*ly7

dy2 ~~ 0*dy2
dy2 ~~ 0*dy3
dy2 ~~ 0*dy4
dy2 ~~ 0*dy5
dy2 ~~ 0*dy6
dy2 ~~ 0*dy7

dy3 ~~ 0*dy3
dy3 ~~ 0*dy4
dy3 ~~ 0*dy5
dy3 ~~ 0*dy6
dy3 ~~ 0*dy7

dy4 ~~ 0*dy4
dy4 ~~ 0*dy5
dy4 ~~ 0*dy6
dy4 ~~ 0*dy7

dy5 ~~ 0*dy5
dy5 ~~ 0*dy6
dy5 ~~ 0*dy7

dy6 ~~ 0*dy6
dy6 ~~ 0*dy7

dy7 ~~ 0*dy7

# manifest variances (made equivalent by naming sigma2u)
math2 ~~ sigma2u*math2
math3 ~~ sigma2u*math3
math4 ~~ sigma2u*math4
math5 ~~ sigma2u*math5
math6 ~~ sigma2u*math6
math7 ~~ sigma2u*math7
math8 ~~ sigma2u*math8

# manifest means (fixed at zero)
math2 ~ 0
math3 ~ 0
math4 ~ 0
math5 ~ 0
math6 ~ 0
math7 ~ 0
math8 ~ 0

"

fit.lcs <- sem(model.syntax,
data=nlsy_math_wide,
missing         = "fiml",
estimator       = "ml"
)
summary(fit.lcs)
## lavaan (0.5-23.1097) converged normally after  32 iterations
##
##                                                   Used       Total
##   Number of observations                           932         933
##
##   Number of missing patterns                        60
##
##   Estimator                                         ML
##   Minimum Function Test Statistic               58.308
##   Degrees of freedom                                28
##   P-value (Chi-square)                           0.001
##
## Parameter Estimates:
##
##   Information                                 Observed
##   Standard Errors                             Standard
##
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ly1 =~
##     math2             1.000
##   ly2 =~
##     math3             1.000
##   ly3 =~
##     math4             1.000
##   ly4 =~
##     math5             1.000
##   ly5 =~
##     math6             1.000
##   ly6 =~
##     math7             1.000
##   ly7 =~
##     math8             1.000
##   dy2 =~
##     ly2               0.000
##   dy3 =~
##     ly3               0.000
##   dy4 =~
##     ly4               0.000
##   dy5 =~
##     ly5               0.000
##   dy6 =~
##     ly6               0.000
##   dy7 =~
##     ly7               0.000
##   g2 =~
##     dy2               1.000
##     dy3               1.000
##     dy4               1.000
##     dy5               1.000
##     dy6               1.000
##     dy7               1.000
##
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ly2 ~
##     ly1               1.000
##     dy2               1.000
##   ly3 ~
##     ly2               1.000
##     dy3               1.000
##   ly4 ~
##     ly3               1.000
##     dy4               1.000
##   ly5 ~
##     ly4               1.000
##     dy5               1.000
##   ly6 ~
##     ly5               1.000
##     dy6               1.000
##   ly7 ~
##     ly6               1.000
##     dy7               1.000
##   dy2 ~
##     ly1       (pi)   -0.241    0.018  -13.387    0.000
##   dy3 ~
##     ly2       (pi)   -0.241    0.018  -13.387    0.000
##   dy4 ~
##     ly3       (pi)   -0.241    0.018  -13.387    0.000
##   dy5 ~
##     ly4       (pi)   -0.241    0.018  -13.387    0.000
##   dy6 ~
##     ly5       (pi)   -0.241    0.018  -13.387    0.000
##   dy7 ~
##     ly6       (pi)   -0.241    0.018  -13.387    0.000
##
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ly1 ~~
##     g2               13.746    1.699    8.092    0.000
##  .dy2 ~~
##    .dy3               0.000
##    .dy4               0.000
##    .dy5               0.000
##    .dy6               0.000
##    .dy7               0.000
##  .dy3 ~~
##    .dy4               0.000
##    .dy5               0.000
##    .dy6               0.000
##    .dy7               0.000
##  .dy4 ~~
##    .dy5               0.000
##    .dy6               0.000
##    .dy7               0.000
##  .dy5 ~~
##    .dy6               0.000
##    .dy7               0.000
##  .dy6 ~~
##    .dy7               0.000
##
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     ly1              32.533    0.434   74.955    0.000
##     g2               15.222    0.815   18.687    0.000
##    .math2             0.000
##    .math3             0.000
##    .math4             0.000
##    .math5             0.000
##    .math6             0.000
##    .math7             0.000
##    .math8             0.000
##    .ly2               0.000
##    .ly3               0.000
##    .ly4               0.000
##    .ly5               0.000
##    .ly6               0.000
##    .ly7               0.000
##    .dy2               0.000
##    .dy3               0.000
##    .dy4               0.000
##    .dy5               0.000
##    .dy6               0.000
##    .dy7               0.000
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     ly1              71.900    6.548   10.980    0.000
##     g2                5.602    0.837    6.695    0.000
##    .ly2               0.000
##    .ly3               0.000
##    .ly4               0.000
##    .ly5               0.000
##    .ly6               0.000
##    .ly7               0.000
##    .dy2               0.000
##    .dy3               0.000
##    .dy4               0.000
##    .dy5               0.000
##    .dy6               0.000
##    .dy7               0.000
##    .math2   (sgm2)   30.818    1.700   18.126    0.000
##    .math3   (sgm2)   30.818    1.700   18.126    0.000
##    .math4   (sgm2)   30.818    1.700   18.126    0.000
##    .math5   (sgm2)   30.818    1.700   18.126    0.000
##    .math6   (sgm2)   30.818    1.700   18.126    0.000
##    .math7   (sgm2)   30.818    1.700   18.126    0.000
##    .math8   (sgm2)   30.818    1.700   18.126    0.000

The result is the same with the OpenMX result on page 417 (output 16.2).

Reference:

Ghisletta, P., & McArdle, J. J. (2012). Teacher’s Corner: Latent Curve Models and Latent Change Score Models Estimated in R. Structural Equation Modeling, 19(4): 651-682. doi:10.1080/10705511.2012.713275.

https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4259494/pdf/nihms412332.pdf