# principles and practice of sem, 5th ed.
# rex b. kline, guilford press, 2023
# chapter 16, table 16.2, analysis 4
# cca of a composite model in the PLS-PM algorithm
# with the OLS estimator
# 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
# ** IMPORTANT **
# the cSEM package creates very long output because it
# writes progress bars for boostrapping to the R console,
# and all that text for each stage of progress can exceed
# the default character limit
# for this analysis in R-4.3.3 for Windows, go to
# Edit | GUI Preferences...
# and in the Rgui Configuration Editor, increase the value for
# buff chars
# from 250000 to 500000
# the value for
# lines
# should be at least 8000
# now run this syntax file
# extraneous text for the progress bars in the original
# output is removed from this file
date()
v <- R.Version()
print(paste0(v$language, " version ", v$major, ".",
v$minor, " (", v$year, "-", v$month, "-", v$day, ")"))
library(semTools)
library(lavaan)
library(cSEM)
library (psych)
# set global seed for random number generation
set.seed(123)
# get citation information
citation("semTools", auto = TRUE)
citation("lavaan", auto = TRUE)
citation("cSEM", auto = TRUE)
citation("psych", auto = TRUE)
# variable order is acculscl, status, percent, educ, income,
# interpers, job, scl90d
# read correlation matrix
shen.cor <- matrix(c(1.00, .44, .69, .21, .23, .12, .09, .03,
.44,1.00, .54, .08, .15, .08, .06, .02,
.69, .54,1.00, .16, .19, .08, .04,-.02,
.21, .08, .16,1.00, .19, .08, .01,-.07,
.23, .15, .19, .19,1.00,-.03,-.02,-.11,
.12, .08, .08, .08,-.03,1.00, .38, .37,
.09, .06, .04, .01,-.02, .38,1.00, .46,
.03, .02,-.02,-.07,-.11, .37, .46,1.00),
ncol = 8, nrow = 8)
# generate raw scores and save to dataframe
shen.data <- semTools::kd(shen.cor, 983, type="exact")
# rename columns in data frame and display correlation matrix
names(shen.data) <- c("acculscl", "status", "percent", "educ", "income",
"interpers", "job", "scl90d")
# display correlation matrix
cor(shen.data)
# descriptive statistics
options(width = 120)
psych::describe(shen.data)
# specify composite model
shen.model <- '
# outer model (measurement)
# exogenous composites
Acculturation <~ acculscl + status + percent
SES <~ educ + income
# endogenous composites
Stress <~ interpers + job
Depression <~ scl90d
# inner model (structural)
Stress ~ Acculturation
Depression ~ SES + Stress '
# fit model to data with package cSEM for cca
# the algorithm is basic PLS-PM
# dominant indicators specified for all composites
# with multiple indicators
# by default, the single indicator for depression
# is the dominant indicator
# outer weights are PLS mode A (correlation weights)
# inner weights are factor (factorial)
# bootstrapped standard errors, 1000 generated samples
# seed for bootstrapping (123) initializes random
# number generation in cSEM functions for boostrapping
# the global seed in R is also set to the same value (123)
# thus, bootstrapped estimates of standard errors and
# percentiles for distributions of global fit test
# statistics are reproducible
shen <- cSEM::csem(.data = shen.data, .model = shen.model,
.dominant_indicators = c(Acculturation = "acculscl", SES = "educ",
Stress = "interpers"), .approach_weights = "PLS-PM",
.PLS_modes = "modeA", .PLS_weight_scheme_inner = "factorial",
.resample_method = "bootstrap", .R = 1000, .seed = 123,
.disattenuate = FALSE)
# check solution for problems
cSEM::verify(shen)
# parameter estimates with bootstrapped standard errors
cSEM::summarize(shen)
# test overall (global) model fit
# 1000 bootstrap replications
# seed value set
cSEM::testOMF(shen, .R = 1000, .seed = 123)
# model quality criteria
cSEM::assess(shen, .quality_criterion = c("df", "r2", "r2_adj", "f2",
"chi_square"))
# model-implied correlations among composites
cSEM::fit(shen, .type_vcv = "construct")
# model-implied correlations among indicators
predicted <- cSEM::fit(shen, .type_vcv = "indicator")
predicted
# calculate correlation residuals
# rounded to 3-decimal places
cor_residuals = shen.cor - predicted
round(cor_residuals, digits = 3)