Load libraries
library(tidyverse)
library(lavaan)
library(semTools)Principles and Practice of Structural Equation Modeling (5e) by Rex B. Kline
library(tidyverse)
library(lavaan)
library(semTools)# read in summary statistics
kimspoonLower.cor <- '
1.00
.35 1.00
.28 .35 1.00
.29 .40 .45 1.00
.00 .07 .14 .04 1.00
.00 -.09 -.12 -.10 .26 1.00 '
# name the variables and convert to full correlation matrix
kimspoon.cor <- lavaan::getCov(kimspoonLower.cor, names = c("R1", "R2",
"R3", "R4", "abuse", "neglect"))
# display the correlations
kimspoon.cor |> print() R1 R2 R3 R4 abuse neglect
R1 1.00 0.35 0.28 0.29 0.00 0.00
R2 0.35 1.00 0.35 0.40 0.07 -0.09
R3 0.28 0.35 1.00 0.45 0.14 -0.12
R4 0.29 0.40 0.45 1.00 0.04 -0.10
abuse 0.00 0.07 0.14 0.04 1.00 0.26
neglect 0.00 -0.09 -0.12 -0.10 0.26 1.00
# add the standard deviations and convert to covariances
kimspoon.cov <- lavaan::cor2cov(kimspoon.cor, sds = c(.05,.77,.76,1.15,
7.75,4.09))
# create mean vector
kimspoon.mean = c(.04,.61,.57,.83,7.17,3.03)
# display the covariances and means
kimspoon.cov |> print()
kimspoon.mean |> print() R1 R2 R3 R4 abuse neglect
R1 0.002500 0.013475 0.010640 0.016675 0.000000 0.000000
R2 0.013475 0.592900 0.204820 0.354200 0.417725 -0.283437
R3 0.010640 0.204820 0.577600 0.393300 0.824600 -0.373008
R4 0.016675 0.354200 0.393300 1.322500 0.356500 -0.470350
abuse 0.000000 0.417725 0.824600 0.356500 60.062500 8.241350
neglect 0.000000 -0.283437 -0.373008 -0.470350 8.241350 16.728100
[1] 0.04 0.61 0.57 0.83 7.17 3.03
# for all models, error variance for R1
# is fixed to equal zero
# lavaan function growth() automatically fixes
# intercepts of indicators to zero but specifies
# latent growth factor means as free parameters
# the direct tracing of the constant (delta-1) on
# the latent growth factors are means but are labeled
# as "intercepts" in lavaan output
# specify all models
# model 1
# no growth (intercept only)
noGrowth.model <- '
# specify intercept
# fix all loadings to 1.0
Intercept =~ 1*R1 + 1*R2 + 1*R3 + 1*R4
# fix error variance for r1 to zero
R1 ~~ 0*R1
'# model 2
# latent basis growth model
# (curve fitting, level and shape)
# this model is retained
# maccallum-rmsea for model 2
# exact fit test
# power at N = 150
semTools::findRMSEApower(0, .05, 4, 150, .05, 1) |> print()
# minimum N for power at least .90
semTools::findRMSEAsamplesize(0, .05, 4, .90, .05, 1) |> print()
basis.model <- '
Intercept =~ 1*R1 + 1*R2 + 1*R3 + 1*R4
# specify shape, first and last loadings fixed
Shape =~ 0*R1 + R2 + R3 + 1*R4
R1 ~~ 0*R1
'[1] 0.136742
[1] 1542
# model 3
# linear growth model
linear.model <- '
Intercept =~ 1*R1 + 1*R2 + 1*R3 + 1*R4
# all loadings fixed to constants
Linear =~ 0*R1 + 1*R2 + 2*R3 + 3*R4
R1 ~~ 0*R1
'# fit model 1 to data
noGrowth <- lavaan::growth(noGrowth.model, sample.cov = kimspoon.cov,
sample.mean = kimspoon.mean, sample.nobs = 150)
# fit model 2 to data
basis <- lavaan::growth(basis.model, sample.cov = kimspoon.cov,
sample.mean = kimspoon.mean, sample.nobs = 150)
# fit model 3 to data
linear <- lavaan::growth(linear.model, sample.cov = kimspoon.cov,
sample.mean = kimspoon.mean, sample.nobs = 150)# model chi-squares and chi-square difference tests
anova(noGrowth, basis) |> print()
Chi-Squared Difference Test
Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
basis 4 610.60 640.71 2.8109
noGrowth 9 865.42 880.47 267.6294 264.82 0.58858 5 < 2.2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
anova(basis, linear) |> print()
Chi-Squared Difference Test
Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
basis 4 610.6 640.71 2.8109
linear 6 638.6 662.69 34.8116 32.001 0.31623 2 1.125e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# model 1 parameter estimates, global fit statistics,
# residuals
# very poor fit
lavaan::summary(noGrowth, fit.measures = TRUE, estimates = FALSE)
lavaan::fitted(noGrowth)
lavaan::residuals(noGrowth, type = "standardized")
lavaan::residuals(noGrowth, type = "cor.bollen")
# model 2 parameter estimates, global fit statistics,
# residuals
# retained model
lavaan::summary(basis, fit.measures = TRUE, rsquare = TRUE)
lavaan::standardizedSolution(basis)
# variance and standard error for Intercept are close to zero,
# so estimates are printed at 5-decimal accuracy, not 3 (default)
print(lavaan::parameterEstimates(basis), nd = 5)# implied covariances and means for observed variables
lavaan::fitted(basis)
# implied means for latent growth factors & observed variables
lavaan::lavInspect(basis, "mean.lv")
lavaan::lavInspect(basis, "mean.ov")# residuals
lavaan::residuals(basis, type = "raw")
lavaan::residuals(basis, type = "standardized")
lavaan::residuals(basis, type = "cor.bollen")# model 3 parameter estimates, global fit statistics,
# residuals
lavaan::summary(linear, fit.measures = TRUE)
lavaan::fitted(linear)
lavaan::residuals(linear, type = "raw")
lavaan::residuals(linear, type = "standardized")
lavaan::residuals(linear, type = "cor.bollen")