This tutorial walks through a few helpful initial steps before conducting nonlinear growth curve analyses (or any analyses for that matter).
The code and example provided in this tutorial are from Chapter 10 of Grimm, Ram, and Estabrook (2016), with a few additions in code and commentary; however, the chpater should be referred to for further interpretations and insights about the analyses.
This tutorial provides line-by-line code to
nlme
nlme
lavaan
lavaan
filepath <- "https://quantdev.ssri.psu.edu/sites/qdev/files/bgs_height_long.csv"
hght_long <- read.csv(file=url(filepath),header=TRUE)
head(hght_long)
## id age hght
## 1 1 1 53.5
## 2 1 3 60.4
## 3 1 6 67.2
## 4 1 9 70.9
## 5 1 12 76.2
## 6 1 15 81.1
Quick descriptives of our dataset
summary(hght_long)
## id age hght
## Min. : 1 Min. : 1.00 Min. : 49.50
## 1st Qu.:21 1st Qu.: 6.00 1st Qu.: 65.00
## Median :42 Median :12.00 Median : 74.20
## Mean :42 Mean :13.78 Mean : 74.34
## 3rd Qu.:63 3rd Qu.:18.00 3rd Qu.: 83.20
## Max. :83 Max. :36.00 Max. :106.00
## NA's :166
Loading necessary libraries
library(nlme)
library(lavaan)
library(ggplot2)
ggplot(hght_long, aes(x = age, y = hght, color = as.factor(id), group = id)) +
geom_point() +
geom_line() +
theme_classic(base_size = 18) +
theme(legend.position = "none") +
labs(title = "Individual Height Trajectories", y = "Height (cm)", x = "Age (months)")
nlme
The first line of code within the nlme()
function resembles formula 10.1, where the outcome variable, hght
, is specified as,
\(y_{ti} = b_{1i} + b_{2i}*((t - k_1)/ k_2) + b_{3i}*((t - k_1)/ k_2)^2 + u_{ti}\)
where \(b_{3i}\) is the quadratic component. Age is centered at 18 months and scaled to years (divided by 12). na.action = na.exclude
omits observations with incomplete values for age
using FIML.
hght.quad.nlme <- nlme(hght~b_1i+b_2i*((age-18)/12)+b_3i*((age-18)/12)^2,
data=hght_long,
fixed=b_1i+b_2i+b_3i~1,
random=b_1i+b_2i+b_3i~1,
groups=~id,
start=c(30, 10, -3),
na.action=na.exclude)
summary(hght.quad.nlme)
## Nonlinear mixed-effects model fit by maximum likelihood
## Model: hght ~ b_1i + b_2i * ((age - 18)/12) + b_3i * ((age - 18)/12)^2
## Data: hght_long
## AIC BIC logLik
## 2505.736 2549.383 -1242.868
##
## Random effects:
## Formula: list(b_1i ~ 1, b_2i ~ 1, b_3i ~ 1)
## Level: id
## Structure: General positive-definite, Log-Cholesky parametrization
## StdDev Corr
## b_1i 2.8722010 b_1i b_2i
## b_2i 0.9542761 0.698
## b_3i 0.4289492 -0.425 -0.944
## Residual 1.5717470
##
## Fixed effects: b_1i + b_2i + b_3i ~ 1
## Value Std.Error DF t-value p-value
## b_1i 83.08276 0.3445299 496 241.14815 0
## b_2i 13.80616 0.1380442 496 100.01263 0
## b_3i -3.43111 0.0976758 496 -35.12752 0
## Correlation:
## b_1i b_2i
## b_2i 0.614
## b_3i -0.419 -0.405
##
## Standardized Within-Group Residuals:
## Min Q1 Med Q3 Max
## -2.63071485 -0.62260082 0.06748581 0.64194540 2.59829087
##
## Number of Observations: 581
## Number of Groups: 83
Quadratic Growth Model without variation in \(b_{3i}\)
hght.quad.nlme <- nlme(hght~b_1i+b_2i*((age-18)/12)+b_3i*((age-18)/12)^2,
data=hght_long,
fixed=b_1i+b_2i+b_3i~1,
random=b_1i+b_2i~1,
groups=~id,
start=c(30, 10, -3),
na.action=na.exclude)
summary(hght.quad.nlme)
## Nonlinear mixed-effects model fit by maximum likelihood
## Model: hght ~ b_1i + b_2i * ((age - 18)/12) + b_3i * ((age - 18)/12)^2
## Data: hght_long
## AIC BIC logLik
## 2515.275 2545.828 -1250.637
##
## Random effects:
## Formula: list(b_1i ~ 1, b_2i ~ 1)
## Level: id
## Structure: General positive-definite, Log-Cholesky parametrization
## StdDev Corr
## b_1i 2.7040353 b_1i
## b_2i 0.8885105 0.62
## Residual 1.6303875
##
## Fixed effects: b_1i + b_2i + b_3i ~ 1
## Value Std.Error DF t-value p-value
## b_1i 83.01636 0.3248686 496 255.5383 0
## b_2i 13.78432 0.1344658 496 102.5117 0
## b_3i -3.42943 0.0870154 496 -39.4118 0
## Correlation:
## b_1i b_2i
## b_2i 0.532
## b_3i -0.249 0.010
##
## Standardized Within-Group Residuals:
## Min Q1 Med Q3 Max
## -2.9850630 -0.5640788 0.1010256 0.6286861 2.8576172
##
## Number of Observations: 581
## Number of Groups: 83
The results are the same as those given in Chapter 10 (p. 213).
nlme
The first line of code within the nlme()
function resembles formula 10.3, where the outcome variable, hght
, is specified as,
\(y_{ti} = b_{1i} + b_{2i}*(min(t - k_1,0)) + b_{3i}*(max(t - k_1,0)) + u_{ti}\)
where \(k_{1}\) is the knot point, \(b_{2i}\) is the random pre knot point slope for an individual, and \(b_{3i}\) is the random post knot point slope for an individual. Here, the knot point is set to 9 months, so we subtract age
by 9. na.action = na.exclude
omits observations with incomplete values for age
using FIML.
hght.spline.nlme <- nlme(hght~b_1i+b_2i*(pmin(0,age-9))+b_3i*(pmax(0,age-9)),
data=hght_long,
fixed=b_1i+b_2i+b_3i~1,
random=b_1i+b_2i+b_3i~1,
groups=~id,
start=c(60, 10, 6),
na.action=na.exclude)
summary(hght.spline.nlme)
## Nonlinear mixed-effects model fit by maximum likelihood
## Model: hght ~ b_1i + b_2i * (pmin(0, age - 9)) + b_3i * (pmax(0, age - 9))
## Data: hght_long
## AIC BIC logLik
## 2359.183 2402.83 -1169.591
##
## Random effects:
## Formula: list(b_1i ~ 1, b_2i ~ 1, b_3i ~ 1)
## Level: id
## Structure: General positive-definite, Log-Cholesky parametrization
## StdDev Corr
## b_1i 2.4747762 b_1i b_2i
## b_2i 0.2088762 0.451
## b_3i 0.0466204 0.727 0.862
## Residual 1.3461151
##
## Fixed effects: b_1i + b_2i + b_3i ~ 1
## Value Std.Error DF t-value p-value
## b_1i 73.35059 0.29455024 496 249.02575 0
## b_2i 2.22669 0.03329293 496 66.88180 0
## b_3i 0.88742 0.00949459 496 93.46634 0
## Correlation:
## b_1i b_2i
## b_2i 0.481
## b_3i 0.208 0.104
##
## Standardized Within-Group Residuals:
## Min Q1 Med Q3 Max
## -2.71701453 -0.56032355 0.06312546 0.63763290 2.54232230
##
## Number of Observations: 581
## Number of Groups: 83
The results are the same as those given in Chapter 10 (p. 217).
Here’s the same spline model. We created new variables pre
and post
which indicate the knot point to use in the model specification.
hght_long$pre = pmin(0,hght_long$age-9)
hght_long$post = pmax(0,hght_long$age-9)
hght.spline2.nlme <- nlme(hght~b_1i+b_2i*pre+b_3i*post,
data=hght_long,
fixed=b_1i+b_2i+b_3i~1,
random=b_1i+b_2i+b_3i~1,
groups=~id,
start=c(60, 10, 6),
na.action=na.exclude)
summary(hght.spline2.nlme)
## Nonlinear mixed-effects model fit by maximum likelihood
## Model: hght ~ b_1i + b_2i * pre + b_3i * post
## Data: hght_long
## AIC BIC logLik
## 2359.183 2402.83 -1169.591
##
## Random effects:
## Formula: list(b_1i ~ 1, b_2i ~ 1, b_3i ~ 1)
## Level: id
## Structure: General positive-definite, Log-Cholesky parametrization
## StdDev Corr
## b_1i 2.4747762 b_1i b_2i
## b_2i 0.2088762 0.451
## b_3i 0.0466204 0.727 0.862
## Residual 1.3461151
##
## Fixed effects: b_1i + b_2i + b_3i ~ 1
## Value Std.Error DF t-value p-value
## b_1i 73.35059 0.29455024 496 249.02575 0
## b_2i 2.22669 0.03329293 496 66.88180 0
## b_3i 0.88742 0.00949459 496 93.46634 0
## Correlation:
## b_1i b_2i
## b_2i 0.481
## b_3i 0.208 0.104
##
## Standardized Within-Group Residuals:
## Min Q1 Med Q3 Max
## -2.71701453 -0.56032355 0.06312546 0.63763290 2.54232230
##
## Number of Observations: 581
## Number of Groups: 83
These results are identical to the previous model.
lavaan
Data set must be in wide format for SEM implementation, so we will use the reshape()
function.
hght_long <- hght_long[,c("id", "age", "hght")] # excluding the pre and post variables we had created
hght_wide <- reshape(hght_long, #data set
v.names='hght', #repeated measures variable
idvar='id', #id variable
timevar='age', #time metric/occasion variable
direction='wide') #direction of re-structuring
names(hght_wide) <- c("id","hght01","hght03", "hght06", "hght09","hght12", "hght15", "hght18", "hght24", "hght36")
head(hght_wide)
## id hght01 hght03 hght06 hght09 hght12 hght15 hght18 hght24 hght36
## 1 1 53.5 60.4 67.2 70.9 76.2 81.1 NA 89.5 95.9
## 10 2 54.5 58.8 66.0 69.1 74.5 78.2 81.2 86.7 NA
## 19 3 49.5 56.0 61.9 64.1 67.9 69.6 73.8 NA 85.1
## 28 4 56.9 64.6 70.0 72.5 76.1 80.4 82.3 87.9 94.3
## 37 5 56.7 63.1 NA 73.1 77.3 81.8 83.5 88.9 99.1
## 46 6 56.1 61.9 67.9 72.3 77.3 79.9 82.3 88.3 97.5
Now, each column aside from the id
column corresponds to one age’s height values.
Age is centered at 18 months and scaled by year. We also provide starting values for the three latent factors to aid in model estimation.
Quad_model <- '
#intercept factor loadings
eta_1 =~ 1*hght01 +
1*hght03 +
1*hght06 +
1*hght09 +
1*hght12 +
1*hght15 +
1*hght18 +
1*hght24 +
1*hght36
#linear change factor loadings
eta_2 =~ -1.4167*hght01 +
-1.25 *hght03 +
-1 *hght06 +
-0.75 *hght09 +
-0.5 *hght12 +
-0.25 *hght15 +
0 *hght18 +
0.5 *hght24 +
1.5 *hght36
#quadratic change factor loadings
eta_3 =~ 2.1169*hght01 +
1.5625*hght03 +
1 *hght06 +
0.5625*hght09 +
0.25 *hght12 +
0.0625 *hght15 +
0 *hght18 +
0.25 *hght24 +
2.25 *hght36
#manifest variances to be same over time
hght01 ~~ theta*hght01
hght03 ~~ theta*hght03
hght06 ~~ theta*hght06
hght09 ~~ theta*hght09
hght12 ~~ theta*hght12
hght15 ~~ theta*hght15
hght18 ~~ theta*hght18
hght24 ~~ theta*hght24
hght36 ~~ theta*hght36
#latent variances
eta_1 ~~ eta_1
eta_2 ~~ eta_2
eta_3 ~~ eta_3
#latent covariances
eta_1 ~~ eta_2
eta_1 ~~ eta_3
eta_2 ~~ eta_3
#latent means
eta_1 ~ start(65)*1*65
eta_2 ~ start(2)*1
eta_3 ~ start(0.1)*1
#manifest means fixed to 0
hght01 ~ 0*1
hght03 ~ 0*1
hght06 ~ 0*1
hght09 ~ 0*1
hght12 ~ 0*1
hght15 ~ 0*1
hght18 ~ 0*1
hght24 ~ 0*1
hght36 ~ 0*1
'
quad_fit <- sem(Quad_model, data = hght_wide, meanstructure = T, mimic="mplus")
## Warning in lav_object_post_check(lavobject): lavaan WARNING: covariance matrix of latent variables
## is not positive definite;
## use inspect(fit,"cov.lv") to investigate.
summary(quad_fit, fit.measures = T, standardized = T)
## lavaan (0.5-22) converged normally after 106 iterations
##
## Number of observations 83
##
## Number of missing patterns 31
##
## Estimator ML
## Minimum Function Test Statistic 574.655
## Degrees of freedom 44
## P-value (Chi-square) 0.000
##
## Model test baseline model:
##
## Minimum Function Test Statistic 955.844
## Degrees of freedom 36
## P-value 0.000
##
## User model versus baseline model:
##
## Comparative Fit Index (CFI) 0.423
## Tucker-Lewis Index (TLI) 0.528
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -1223.069
## Loglikelihood unrestricted model (H1) -935.741
##
## Number of free parameters 10
## Akaike (AIC) 2466.138
## Bayesian (BIC) 2490.326
## Sample-size adjusted Bayesian (BIC) 2458.783
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.381
## 90 Percent Confidence Interval 0.354 0.409
## P-value RMSEA <= 0.05 0.000
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.976
##
## Parameter Estimates:
##
## Information Observed
## Standard Errors Standard
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## eta_1 =~
## hght01 1.000 2.873 1.026
## hght03 1.000 2.873 1.048
## hght06 1.000 2.873 1.045
## hght09 1.000 2.873 1.016
## hght12 1.000 2.873 0.973
## hght15 1.000 2.873 0.927
## hght18 1.000 2.873 0.883
## hght24 1.000 2.873 0.814
## hght36 1.000 2.873 0.761
## eta_2 =~
## hght01 -1.417 -1.355 -0.484
## hght03 -1.250 -1.196 -0.436
## hght06 -1.000 -0.956 -0.348
## hght09 -0.750 -0.717 -0.254
## hght12 -0.500 -0.478 -0.162
## hght15 -0.250 -0.239 -0.077
## hght18 0.000 0.000 0.000
## hght24 0.500 0.478 0.136
## hght36 1.500 1.435 0.380
## eta_3 =~
## hght01 2.117 0.717 0.256
## hght03 1.562 0.529 0.193
## hght06 1.000 0.339 0.123
## hght09 0.562 0.191 0.067
## hght12 0.250 0.085 0.029
## hght15 0.062 0.021 0.007
## hght18 0.000 0.000 0.000
## hght24 0.250 0.085 0.024
## hght36 2.250 0.762 0.202
##
## Covariances:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## eta_1 ~~
## eta_2 1.967 0.500 3.931 0.000 0.716 0.716
## eta_3 -0.468 0.296 -1.580 0.114 -0.481 -0.481
## eta_2 ~~
## eta_3 -0.411 0.122 -3.378 0.001 -1.268 -1.268
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## (Eieee:cnff") 83.075 0.343 241.977 0.000 28.913 28.913
## 13.760 0.137 100.344 0.000 14.386 14.386
## -3.389 0.089 -38.066 0.000 -10.002 -10.002
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
## . 0.000 0.000 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## .hght01 (thet) 2.325 0.176 13.203 0.000 2.325 0.296
## .hght03 (thet) 2.325 0.176 13.203 0.000 2.325 0.309
## .hght06 (thet) 2.325 0.176 13.203 0.000 2.325 0.307
## .hght09 (thet) 2.325 0.176 13.203 0.000 2.325 0.291
## .hght12 (thet) 2.325 0.176 13.203 0.000 2.325 0.267
## .hght15 (thet) 2.325 0.176 13.203 0.000 2.325 0.242
## .hght18 (thet) 2.325 0.176 13.203 0.000 2.325 0.220
## .hght24 (thet) 2.325 0.176 13.203 0.000 2.325 0.187
## .hght36 (thet) 2.325 0.176 13.203 0.000 2.325 0.163
## eta_1 8.256 1.497 5.517 0.000 1.000 1.000
## eta_2 0.915 0.242 3.783 0.000 1.000 1.000
## eta_3 0.115 0.108 1.063 0.288 1.000 1.000
We get a warning from lavaan
that the covariance of latent variables is not positive definite, so we will constrain the variance of \(eta_3\) similiar to the variance constraint implemented in the quadratic multilevel model.
Adjusting the factor variance-covariance structure
Quad_model_adjusted <- '
#intercept factor loadings
eta_1 =~ 1*hght01 +
1*hght03 +
1*hght06 +
1*hght09 +
1*hght12 +
1*hght15 +
1*hght18 +
1*hght24 +
1*hght36
#linear change factor loadings
eta_2 =~ -1.4167*hght01 +
-1.25 *hght03 +
-1 *hght06 +
-0.75 *hght09 +
-0.5 *hght12 +
-0.25 *hght15 +
0 *hght18 +
0.5 *hght24 +
1.5 *hght36
#quadratic change factor loadings
eta_3 =~ 2.1169*hght01 +
1.5625*hght03 +
1 *hght06 +
0.5625*hght09 +
0.25 *hght12 +
0.0625 *hght15 +
0 *hght18 +
0.25 *hght24 +
2.25 *hght36
#manifest variances to be same over time
hght01 ~~ start(1)*theta*hght01
hght03 ~~ theta*hght03
hght06 ~~ theta*hght06
hght09 ~~ theta*hght09
hght12 ~~ theta*hght12
hght15 ~~ theta*hght15
hght18 ~~ theta*hght18
hght24 ~~ theta*hght24
hght36 ~~ theta*hght36
#latent variances
eta_1 ~~ eta_1
eta_2 ~~ eta_2
eta_3 ~~ 0*eta_3 #fixing the variance to 0
#latent covariances
eta_1 ~~ eta_2
eta_1 ~~ 0*eta_3 #fixing the covariance to 0
eta_2 ~~ 0*eta_3 #fixing the covariance to 0
#latent means
eta_1 ~ start(65)*1
eta_2 ~ start(2)*1
eta_3 ~ start(0.1)*1
#manifest means fixed to 0
hght01 ~ 0*1
hght03 ~ 0*1
hght06 ~ 0*1
hght09 ~ 0*1
hght12 ~ 0*1
hght15 ~ 0*1
hght18 ~ 0*1
hght24 ~ 0*1
hght36 ~ 0*1
'
quad_fit_adjusted <- sem(Quad_model_adjusted, data = hght_wide, meanstructure = T, mimic="mplus")
summary(quad_fit_adjusted, fit.measures = T, standardized = T)
## lavaan (0.5-22) converged normally after 45 iterations
##
## Number of observations 83
##
## Number of missing patterns 31
##
## Estimator ML
## Minimum Function Test Statistic 593.684
## Degrees of freedom 47
## P-value (Chi-square) 0.000
##
## Model test baseline model:
##
## Minimum Function Test Statistic 955.844
## Degrees of freedom 36
## P-value 0.000
##
## User model versus baseline model:
##
## Comparative Fit Index (CFI) 0.406
## Tucker-Lewis Index (TLI) 0.545
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -1232.583
## Loglikelihood unrestricted model (H1) -935.741
##
## Number of free parameters 7
## Akaike (AIC) 2479.166
## Bayesian (BIC) 2496.098
## Sample-size adjusted Bayesian (BIC) 2474.018
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.374
## 90 Percent Confidence Interval 0.348 0.402
## P-value RMSEA <= 0.05 0.000
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.910
##
## Parameter Estimates:
##
## Information Observed
## Standard Errors Standard
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## eta_1 =~
## hght01 1.000 2.712 1.014
## hght03 1.000 2.712 1.004
## hght06 1.000 2.712 0.984
## hght09 1.000 2.712 0.960
## hght12 1.000 2.712 0.931
## hght15 1.000 2.712 0.899
## hght18 1.000 2.712 0.866
## hght24 1.000 2.712 0.799
## hght36 1.000 2.712 0.674
## eta_2 =~
## hght01 -1.417 -1.287 -0.481
## hght03 -1.250 -1.135 -0.420
## hght06 -1.000 -0.908 -0.330
## hght09 -0.750 -0.681 -0.241
## hght12 -0.500 -0.454 -0.156
## hght15 -0.250 -0.227 -0.075
## hght18 0.000 0.000 0.000
## hght24 0.500 0.454 0.134
## hght36 1.500 1.362 0.338
## eta_3 =~
## hght01 2.117 0.000 0.000
## hght03 1.562 0.000 0.000
## hght06 1.000 0.000 0.000
## hght09 0.562 0.000 0.000
## hght12 0.250 0.000 0.000
## hght15 0.062 0.000 0.000
## hght18 0.000 0.000 0.000
## hght24 0.250 0.000 0.000
## hght36 2.250 0.000 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## eta_1 ~~
## eta_2 1.519 0.431 3.527 0.000 0.617 0.617
## eta_3 0.000 NaN NaN
## eta_2 ~~
## eta_3 0.000 NaN NaN
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## eta_1 83.008 0.323 256.810 0.000 30.606 30.606
## eta_2 13.730 0.135 102.058 0.000 15.117 15.117
## eta_3 -3.395 0.082 -41.497 0.000 -Inf -Inf
## .hght01 0.000 0.000 0.000
## .hght03 0.000 0.000 0.000
## .hght06 0.000 0.000 0.000
## .hght09 0.000 0.000 0.000
## .hght12 0.000 0.000 0.000
## .hght15 0.000 0.000 0.000
## .hght18 0.000 0.000 0.000
## .hght24 0.000 0.000 0.000
## .hght36 0.000 0.000 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## .hght01 (thet) 2.447 0.169 14.453 0.000 2.447 0.342
## .hght03 (thet) 2.447 0.169 14.453 0.000 2.447 0.335
## .hght06 (thet) 2.447 0.169 14.453 0.000 2.447 0.322
## .hght09 (thet) 2.447 0.169 14.453 0.000 2.447 0.306
## .hght12 (thet) 2.447 0.169 14.453 0.000 2.447 0.288
## .hght15 (thet) 2.447 0.169 14.453 0.000 2.447 0.269
## .hght18 (thet) 2.447 0.169 14.453 0.000 2.447 0.250
## .hght24 (thet) 2.447 0.169 14.453 0.000 2.447 0.212
## .hght36 (thet) 2.447 0.169 14.453 0.000 2.447 0.151
## eta_1 7.356 1.263 5.825 0.000 1.000 1.000
## eta_2 0.825 0.227 3.627 0.000 1.000 1.000
## eta_3 0.000 NaN NaN
The results are the same as those given in Chapter 10 (p. 225-7).
lavaan
Spline_model <- '
#intercept factor loadings
eta_1 =~ 1*hght01 +
1*hght03 +
1*hght06 +
1*hght09 +
1*hght12 +
1*hght15 +
1*hght18 +
1*hght24 +
1*hght36
#pre knot linear change factor loadings
eta_2 =~ -8*hght01 +
-6*hght03 +
-3*hght06 +
0*hght09 +
0*hght12 +
0*hght15 +
0*hght18 +
0*hght24 +
0*hght36
#post knot linear change factor loadings
eta_3 =~ 0 *hght01 +
0 *hght03 +
0 *hght06 +
0 *hght09 +
3 *hght12 +
9 *hght18 +
6 *hght15 +
15*hght24 +
27*hght36
#manifest variances to be same over time
hght01 ~~ start(1)*theta*hght01
hght03 ~~ theta*hght03
hght06 ~~ theta*hght06
hght09 ~~ theta*hght09
hght12 ~~ theta*hght12
hght15 ~~ theta*hght15
hght18 ~~ theta*hght18
hght24 ~~ theta*hght24
hght36 ~~ theta*hght36
#latent variances
eta_1 ~~ start(1)*eta_1
eta_2 ~~ eta_2
eta_3 ~~ eta_3
#latent means
eta_1 ~ start(65)*1
eta_2 ~ start(2)*1
eta_3 ~ start(0.1)*1
#manifest means fixed to 0
hght01 ~ 0*1
hght03 ~ 0*1
hght06 ~ 0*1
hght09 ~ 0*1
hght12 ~ 0*1
hght15 ~ 0*1
hght18 ~ 0*1
hght24 ~ 0*1
hght36 ~ 0*1
'
Running the spline model
spline_fit <- sem(Spline_model, data = hght_wide, mimic="mplus")
summary(spline_fit)
## lavaan (0.5-22) converged normally after 55 iterations
##
## Number of observations 83
##
## Number of missing patterns 31
##
## Estimator ML
## Minimum Function Test Statistic 467.700
## Degrees of freedom 44
## P-value (Chi-square) 0.000
##
## Parameter Estimates:
##
## Information Observed
## Standard Errors Standard
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## eta_1 =~
## hght01 1.000
## hght03 1.000
## hght06 1.000
## hght09 1.000
## hght12 1.000
## hght15 1.000
## hght18 1.000
## hght24 1.000
## hght36 1.000
## eta_2 =~
## hght01 -8.000
## hght03 -6.000
## hght06 -3.000
## hght09 0.000
## hght12 0.000
## hght15 0.000
## hght18 0.000
## hght24 0.000
## hght36 0.000
## eta_3 =~
## hght01 0.000
## hght03 0.000
## hght06 0.000
## hght09 0.000
## hght12 3.000
## hght18 9.000
## hght15 6.000
## hght24 15.000
## hght36 27.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## eta_1 ~~
## eta_2 0.233 0.096 2.435 0.015
## eta_3 0.084 0.025 3.327 0.001
## eta_2 ~~
## eta_3 0.008 0.003 3.037 0.002
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## eta_1 73.351 0.294 249.542 0.000
## eta_2 2.227 0.033 66.772 0.000
## eta_3 0.887 0.010 93.397 0.000
## .hght01 0.000
## .hght03 0.000
## .hght06 0.000
## .hght09 0.000
## .hght12 0.000
## .hght15 0.000
## .hght18 0.000
## .hght24 0.000
## .hght36 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .hght01 (thet) 1.812 0.136 13.369 0.000
## .hght03 (thet) 1.812 0.136 13.369 0.000
## .hght06 (thet) 1.812 0.136 13.369 0.000
## .hght09 (thet) 1.812 0.136 13.369 0.000
## .hght12 (thet) 1.812 0.136 13.369 0.000
## .hght15 (thet) 1.812 0.136 13.369 0.000
## .hght18 (thet) 1.812 0.136 13.369 0.000
## .hght24 (thet) 1.812 0.136 13.369 0.000
## .hght36 (thet) 1.812 0.136 13.369 0.000
## eta_1 6.125 1.099 5.572 0.000
## eta_2 0.044 0.014 3.107 0.002
## eta_3 0.002 0.001 2.003 0.045
The results are the same as those given in Chapter 10 (p. 228-31).
Overall, this tutorial provides two nonlinear methods (quadratic growth models and spline models) and two frameworks (multilevel modeling and structural equation modeling) with which to characterize longitudinal measures.