# principles and practice of sem, 5th ed.
# rex b. kline, guilford press, 2023
# chapter 9, table 9.1, analysis 2
# global estimation of the covariance and mean structures
# in the roth et al. (1989) parametric path model of illness
# to avoid the problem that some R packages share the same name
# for different functions, all functions are specified next as
# package::function
# which prevents masking, or the default hiding of
# a function with a redundant name from a package used next
date()
v <- R.Version()
print(paste0(v$language, " version ", v$major, ".",
v$minor, " (", v$year, "-", v$month, "-", v$day, ")"))
library(lavaan)
# get citation information
citation("lavaan", auto = TRUE)
# input the correlations in lower diagnonal form
rothLower.cor <- '
1.00
-.03 1.00
.39 .07 1.00
-.05 -.23 -.13 1.00
-.08 -.16 -.29 .34 1.00 '
# name the variables and convert to full correlation matrix
roth.cor <- lavaan::getCov(rothLower.cor, names = c("exercise", "hardy",
"fitness", "stress", "illness"))
# display the correlations
roth.cor
# add the standard deviations and convert to covariances
roth.cov <- lavaan::cor2cov(roth.cor, sds = c(66.50,38.00,18.40,33.50,62.48))
roth.mean <- c(40.9,0,67.1,24.0,71.67)
# display the covariances and means
roth.cov
roth.mean
# specify path model
roth.model <- '
# regressions
fitness ~ a*exercise
stress ~ c*hardy
illness ~ b*fitness + d*stress
# unanalyzed association between exercise and hardy
# automatically specified
# specify indirect effects on illness
ab := a*b
cd := c*d '
# fit model to sample covariance matrix and means, N = 373
# variances and covariance of measured exogenous
# variables are free parameters
# variances calculated with N - 1 in the denominator instead of N
# default information matrix is expected
# meanstructure = TRUE specifies that intercepts for endogenous
# variables and means for exogenous variables are estimated
roth <- lavaan::sem(roth.model, sample.cov = roth.cov,
sample.mean = roth.mean, sample.nobs = 373, fixed.x = FALSE,
sample.cov.rescale = FALSE, meanstructure = TRUE)
# check for negative error variances
# TRUE in output means no negative variances
lavaan::lavInspect(roth, add.labels = TRUE, "post.check")
# request output
# intercepts and means are the only new results
# values for exercise and hardy (exogenous) listed as
# intercepts are actually means
lavaan::summary(roth, fit.measures = TRUE, rsquare = TRUE)
# generate predicted covariance matrix, predicted means
# df = 0 for mean structure so observed = predicted means
lavaan::fitted(roth)