| Title: | Latent Interaction (and Moderation) Analysis in Structural Equation Models (SEM) |
|---|---|
| Description: | Estimation of interaction (i.e., moderation) effects between latent variables in structural equation models (SEM). The supported methods are: The constrained approach (Algina & Moulder, 2001). The unconstrained approach (Marsh et al., 2004). The residual centering approach (Little et al., 2006). The double centering approach (Lin et al., 2010). The latent moderated structural equations (LMS) approach (Klein & Moosbrugger, 2000). The quasi-maximum likelihood (QML) approach (Klein & Muthén, 2007) The constrained- unconstrained, residual- and double centering- approaches are estimated via 'lavaan' (Rosseel, 2012), whilst the LMS- and QML- approaches are estimated via 'modsem' it self. Alternatively model can be estimated via 'Mplus' (Muthén & Muthén, 1998-2017). References: Algina, J., & Moulder, B. C. (2001). <doi:10.1207/S15328007SEM0801_3>. "A note on estimating the Jöreskog-Yang model for latent variable interaction using 'LISREL' 8.3." Klein, A., & Moosbrugger, H. (2000). <doi:10.1007/BF02296338>. "Maximum likelihood estimation of latent interaction effects with the LMS method." Klein, A. G., & Muthén, B. O. (2007). <doi:10.1080/00273170701710205>. "Quasi-maximum likelihood estimation of structural equation models with multiple interaction and quadratic effects." Lin, G. C., Wen, Z., Marsh, H. W., & Lin, H. S. (2010). <doi:10.1080/10705511.2010.488999>. "Structural equation models of latent interactions: Clarification of orthogonalizing and double-mean-centering strategies." Little, T. D., Bovaird, J. A., & Widaman, K. F. (2006). <doi:10.1207/s15328007sem1304_1>. "On the merits of orthogonalizing powered and product terms: Implications for modeling interactions among latent variables." Marsh, H. W., Wen, Z., & Hau, K. T. (2004). <doi:10.1037/1082-989X.9.3.275>. "Structural equation models of latent interactions: evaluation of alternative estimation strategies and indicator construction." Muthén, L.K. and Muthén, B.O. (1998-2017). "'Mplus' User’s Guide. Eighth Edition." <https://www.statmodel.com/>. Rosseel Y (2012). <doi:10.18637/jss.v048.i02>. "'lavaan': An R Package for Structural Equation Modeling." |
| Authors: | Kjell Solem Slupphaug [aut, cre] (ORCID: <https://orcid.org/0009-0005-8324-2834>), Mehmet Mehmetoglu [ctb] (ORCID: <https://orcid.org/0000-0002-6092-8551>), Matthias Mittner [ctb] (ORCID: <https://orcid.org/0000-0003-0205-7353>) |
| Maintainer: | Kjell Solem Slupphaug <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.20 |
| Built: | 2026-05-31 15:25:48 UTC |
| Source: | https://github.com/kss2k/modsem |
A generic interface for parametric and non-parametric bootstrap procedures
for structural equation models estimated with the modsem ecosystem.
The function dispatches on the class of model; currently dedicated
methods exist for modsem_pi (product‑indicator approach) and
modsem_da (distributional‑analytic approach).
bootstrap_modsem(model = modsem, FUN, ...) ## S3 method for class 'modsem_pi' bootstrap_modsem(model, FUN = "coef", ...) ## S3 method for class 'modsem_da' bootstrap_modsem( model, FUN = "coef", R = 1000L, P.max = 1e+05, type = c("nonparametric", "parametric"), verbose = interactive(), calc.se = FALSE, optimize = FALSE, ... ) ## S3 method for class ''function'' bootstrap_modsem( model = modsem, FUN = "coef", data, R = 1000L, verbose = interactive(), FUN.args = list(), cluster.boot = NULL, ... )bootstrap_modsem(model = modsem, FUN, ...) ## S3 method for class 'modsem_pi' bootstrap_modsem(model, FUN = "coef", ...) ## S3 method for class 'modsem_da' bootstrap_modsem( model, FUN = "coef", R = 1000L, P.max = 1e+05, type = c("nonparametric", "parametric"), verbose = interactive(), calc.se = FALSE, optimize = FALSE, ... ) ## S3 method for class ''function'' bootstrap_modsem( model = modsem, FUN = "coef", data, R = 1000L, verbose = interactive(), FUN.args = list(), cluster.boot = NULL, ... )
model |
A fitted |
FUN |
A function that returns the statistic of interest when applied to a fitted model. The function must accept a single argument, the model object, and should ideally return a numeric vector; see Value. |
... |
Additional arguments forwarded to |
R |
number of bootstrap replicates. |
P.max |
ceiling for the simulated population size. |
type |
Bootstrap flavour, see Details. |
verbose |
Should progress information be printed to the console? |
calc.se |
Should standard errors for each replicate. Defaults to |
optimize |
Should starting values be re-optimized for each replicate. Defaults to |
data |
Dataset to be resampled. |
FUN.args |
Arguments passed to |
cluster.boot |
Variable to cluster bootstrapping by |
A thin wrapper around lavaan::bootstrapLavaan() that performs the
necessary book‑keeping so that FUN receives a fully‑featured
modsem_pi object—rather than a bare lavaan fit—at every
iteration.
The function internally resamples the observed data (non-parametric
case) or simulates from the estimated parameter table (parametric case),
feeds the sample to modsem_da, evaluates FUN on the
refitted object and finally collates the results.
This is a more general version of boostrap_modsem for
bootstrapping modsem functions, not modsem objects.
model is now a function to be boostrapped, and ...
are now passed to the function (model), not FUN. To
pass arguments to FUN use FUN.args.
Depending on the return type of FUN either
A matrix with R rows (bootstrap replicates) and as
many columns as length(FUN(model)).
A list of length R; each element is the raw output of
FUN. NOTE: Only applies for modsem_da objects
bootstrap_modsem(modsem_pi): Bootstrap a modsem_pi model by delegating
to bootstrapLavaan.
bootstrap_modsem(modsem_da): Parametric or non-parametric bootstrap for
modsem_da models.
bootstrap_modsem(`function`): Non-parametric bootstrap of modsem functions
bootstrapLavaan, modsem_pi,
modsem_da
m1 <- ' X =~ x1 + x2 Z =~ z1 + z2 Y =~ y1 + y2 Y ~ X + Z + X:Z ' fit_pi <- modsem(m1, oneInt) bootstrap_modsem(fit_pi, FUN = coef, R = 10L) m1 <- ' X =~ x1 + x2 Z =~ z1 + z2 Y =~ y1 + y2 Y ~ X + Z + X:Z ' ## Not run: fit_lms <- modsem(m1, oneInt, method = "lms") bootstrap_modsem(fit_lms, FUN = coef, R = 10L) ## End(Not run) tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC + INT:PBC " ## Not run: boot <- bootstrap_modsem(model = modsem, model.syntax = tpb, data = TPB, method = "dblcent", rcs = TRUE, rcs.scale.corrected = TRUE, FUN = "coef", R = 50L) coef <- apply(boot, MARGIN = 2, FUN = mean, na.rm = TRUE) se <- apply(boot, MARGIN = 2, FUN = sd, na.rm = TRUE) cat("Parameter Estimates:\n") print(coef) cat("Standard Errors: \n") print(se) ## End(Not run)m1 <- ' X =~ x1 + x2 Z =~ z1 + z2 Y =~ y1 + y2 Y ~ X + Z + X:Z ' fit_pi <- modsem(m1, oneInt) bootstrap_modsem(fit_pi, FUN = coef, R = 10L) m1 <- ' X =~ x1 + x2 Z =~ z1 + z2 Y =~ y1 + y2 Y ~ X + Z + X:Z ' ## Not run: fit_lms <- modsem(m1, oneInt, method = "lms") bootstrap_modsem(fit_lms, FUN = coef, R = 10L) ## End(Not run) tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC + INT:PBC " ## Not run: boot <- bootstrap_modsem(model = modsem, model.syntax = tpb, data = TPB, method = "dblcent", rcs = TRUE, rcs.scale.corrected = TRUE, FUN = "coef", R = 50L) coef <- apply(boot, MARGIN = 2, FUN = mean, na.rm = TRUE) se <- apply(boot, MARGIN = 2, FUN = sd, na.rm = TRUE) cat("Parameter Estimates:\n") print(coef) cat("Standard Errors: \n") print(se) ## End(Not run)
Computes centered estimates of model parameters. This is relevant when there is an
interaction term in the model, as the simple main effects depend upon the mean structure
of the structural model. Currenlty only available for
modsem_da and lavaan object.
It is not relevant for the PI approaches (excluding the "pind" method, which is not recommended),
since the indicators are centered before computing the product terms.
The centering can be applied to observed variable interactions in lavaan models
and latent interactions estimated using the sam function.
centered_estimates(object, ...) ## S3 method for class 'lavaan' centered_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, ... ) ## S3 method for class 'modsem_da' centered_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, ... )centered_estimates(object, ...) ## S3 method for class 'lavaan' centered_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, ... ) ## S3 method for class 'modsem_da' centered_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, ... )
object |
An object of class |
... |
Additional arguments passed to underlying methods. See specific method documentation for supported arguments, including: |
monte.carlo |
Logical. If |
mc.reps |
Number of Monte Carlo repetitions. Default is 10000. |
tolerance.zero |
Threshold below which standard errors are set to |
A data.frame with centered estimates in the est column.
centered_estimates(lavaan): Method for lavaan objects
centered_estimates(modsem_da): Method for modsem_da objects
m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") centered_estimates(est_lms) ## End(Not run)m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") centered_estimates(est_lms) ## End(Not run)
Capture, colorise, and emit console text
colorize_output( expr, positive = MODSEM_COLORS$positive, negative = MODSEM_COLORS$negative, true = MODSEM_COLORS$true, false = MODSEM_COLORS$false, nan = MODSEM_COLORS$nan, na = MODSEM_COLORS$na, inf = MODSEM_COLORS$inf, string = MODSEM_COLORS$string, split = FALSE, append = "\n" )colorize_output( expr, positive = MODSEM_COLORS$positive, negative = MODSEM_COLORS$negative, true = MODSEM_COLORS$true, false = MODSEM_COLORS$false, nan = MODSEM_COLORS$nan, na = MODSEM_COLORS$na, inf = MODSEM_COLORS$inf, string = MODSEM_COLORS$string, split = FALSE, append = "\n" )
expr |
Expression or object with output which should be colorized. |
positive |
color of positive numbers. |
negative |
color of negative numbers. |
true |
color of |
false |
color of |
nan |
color of |
na |
color of |
inf |
color of |
string |
color of quoted strings. |
split |
Should output be splitted? If |
append |
String appended after the colored output (default '\n'). |
Invisibly returns the *plain* captured text.
set_modsem_colors(positive = "red3", negative = "red3", true = "darkgreen", false = "red3", na = "purple", string = "darkgreen") m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est <- modsem(m1, data = oneInt) colorize_output(summary(est)) colorize_output(est) # same as colorize_output(print(est)) colorize_output(modsem_inspect(est, what = "coef")) ## Not run: colorize_output(split = TRUE, { # Get live (uncolored) output # And print colored output at the end of execution est_lms <- modsem(m1, data = oneInt, method = "lms") summary(est_lms) }) colorize_output(modsem_inspect(est_lms)) ## End(Not run)set_modsem_colors(positive = "red3", negative = "red3", true = "darkgreen", false = "red3", na = "purple", string = "darkgreen") m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est <- modsem(m1, data = oneInt) colorize_output(summary(est)) colorize_output(est) # same as colorize_output(print(est)) colorize_output(modsem_inspect(est, what = "coef")) ## Not run: colorize_output(split = TRUE, { # Get live (uncolored) output # And print colored output at the end of execution est_lms <- modsem(m1, data = oneInt, method = "lms") summary(est_lms) }) colorize_output(modsem_inspect(est_lms)) ## End(Not run)
modsem modelsCompare the fit of two models using the likelihood ratio test (LRT).
est_h0 is the null hypothesis model, and est_h1 the alternative hypothesis model.
Importantly, the function assumes that est_h0 does not have more free parameters
(i.e., degrees of freedom) than est_h1 (the alternative hypothesis model).
compare_fit(est_h1, est_h0, ...)compare_fit(est_h1, est_h0, ...)
est_h1 |
object of class |
est_h0 |
object of class |
... |
additional arguments passed to the underlying comparison function. E.g.,
for |
## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " # LMS approach est_h1 <- modsem(m1, oneInt, "lms") est_h0 <- estimate_h0(est_h1, calc.se=FALSE) # std.errors are not needed compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Double centering approach est_h1 <- modsem(m1, oneInt, method = "dblcent") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Constrained approach est_h1 <- modsem(m1, oneInt, method = "ca") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) ## End(Not run)## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " # LMS approach est_h1 <- modsem(m1, oneInt, "lms") est_h0 <- estimate_h0(est_h1, calc.se=FALSE) # std.errors are not needed compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Double centering approach est_h1 <- modsem(m1, oneInt, method = "dblcent") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Constrained approach est_h1 <- modsem(m1, oneInt, method = "ca") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) ## End(Not run)
This function returns the default settings for the LMS and QML approach.
default_settings_da(method = c("lms", "qml"))default_settings_da(method = c("lms", "qml"))
method |
which method to get the settings for |
list
library(modsem) default_settings_da()library(modsem) default_settings_da()
This function returns the default settings for the product indicator approaches
default_settings_pi(method = c("rca", "uca", "pind", "dblcent", "ca"))default_settings_pi(method = c("rca", "uca", "pind", "dblcent", "ca"))
method |
which method to get the settings for |
list
library(modsem) default_settings_pi()library(modsem) default_settings_pi()
modsem modelsEstimates a baseline model (H0) from a given model (H1). The baseline model is estimated by removing all interaction terms from the model.
estimate_h0(object, warn_no_interaction = TRUE, ...) ## S3 method for class 'modsem_da' estimate_h0(object, warn_no_interaction = TRUE, ...) ## S3 method for class 'modsem_pi' estimate_h0(object, warn_no_interaction = TRUE, reduced = TRUE, ...)estimate_h0(object, warn_no_interaction = TRUE, ...) ## S3 method for class 'modsem_da' estimate_h0(object, warn_no_interaction = TRUE, ...) ## S3 method for class 'modsem_pi' estimate_h0(object, warn_no_interaction = TRUE, reduced = TRUE, ...)
object |
|
warn_no_interaction |
Logical. If 'TRUE', a warning is issued if no interaction terms are found in the model. |
... |
Additional arguments passed to the 'modsem_da' function, overriding the arguments in the original model. |
reduced |
Should the baseline model be a reduced version of the model?
If |
estimate_h0(modsem_da): Estimate baseline model for modsem_da objects
estimate_h0(modsem_pi): Estimate baseline model for modsem_pi objects
## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " # LMS approach est_h1 <- modsem(m1, oneInt, "lms") est_h0 <- estimate_h0(est_h1, calc.se=FALSE) # std.errors are not needed compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Double centering approach est_h1 <- modsem(m1, oneInt, method = "dblcent") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Constrained approach est_h1 <- modsem(m1, oneInt, method = "ca") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) ## End(Not run)## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " # LMS approach est_h1 <- modsem(m1, oneInt, "lms") est_h0 <- estimate_h0(est_h1, calc.se=FALSE) # std.errors are not needed compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Double centering approach est_h1 <- modsem(m1, oneInt, method = "dblcent") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) # Constrained approach est_h1 <- modsem(m1, oneInt, method = "ca") est_h0 <- estimate_h0(est_h1, oneInt) compare_fit(est_h1 = est_h1, est_h0 = est_h0) ## End(Not run)
extract lavaan object from modsem object estimated using product indicators
extract_lavaan(object)extract_lavaan(object)
object |
modsem object |
lavaan object
library(modsem) m1 <- ' # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' est <- modsem_pi(m1, oneInt) lav_est <- extract_lavaan(est)library(modsem) m1 <- ' # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' est <- modsem_pi(m1, oneInt) lav_est <- extract_lavaan(est)
Calculates chi-sq test and p-value, as well as RMSEA for the LMS and QML models. Note that the Chi-Square based fit measures should be calculated for the baseline model, i.e., the model without the interaction effect
fit_modsem_da( model, chisq = TRUE, lav.fit = FALSE, drop.list.single.group = TRUE )fit_modsem_da( model, chisq = TRUE, lav.fit = FALSE, drop.list.single.group = TRUE )
model |
fitted model. Thereafter, you can use 'compare_fit()' to assess the comparative fit of the models. If the interaction effect makes the model better, and e.g., the RMSEA is good for the baseline model, the interaction model likely has a good RMSEA as well. |
chisq |
should Chi-Square based fit-measures be calculated? |
lav.fit |
Should fit indices from the |
drop.list.single.group |
Logical. If FALSE, (some) results are returned as a list, where each element corresponds to a group (even if there is only a single group). If TRUE, the list will be unlisted if there is only a single group |
get_pi_data() is a function for creating a dataset with product indiactors used for estimating
latent interaction models using one of the product indicator approaches.
get_pi_data(model.syntax, data, method = "dblcent", match = FALSE, ...)get_pi_data(model.syntax, data, method = "dblcent", match = FALSE, ...)
model.syntax |
|
data |
data to create product indicators from |
method |
method to use:
|
match |
should the product indicators be created by using the match-strategy |
... |
arguments passed to other functions (e.g., modsem_pi) |
data.frame
library(modsem) library(lavaan) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' syntax <- get_pi_syntax(m1) data <- get_pi_data(m1, oneInt) est <- sem(syntax, data) summary(est)library(modsem) library(lavaan) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' syntax <- get_pi_syntax(m1) data <- get_pi_data(m1, oneInt) est <- sem(syntax, data) summary(est)
lavaan syntax for product indicator approachesget_pi_syntax() is a function for creating the lavaan syntax used for estimating
latent interaction models using one of the product indicator approaches.
get_pi_syntax( model.syntax, method = "dblcent", match = FALSE, data = NULL, ... )get_pi_syntax( model.syntax, method = "dblcent", match = FALSE, data = NULL, ... )
model.syntax |
|
method |
method to use:
|
match |
should the product indicators be created by using the match-strategy |
data |
Optional. Dataset to use, usually not relevant. |
... |
arguments passed to other functions (e.g., modsem_pi) |
character vector
library(modsem) library(lavaan) m1 <- ' # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' syntax <- get_pi_syntax(m1) data <- get_pi_data(m1, oneInt) est <- sem(syntax, data) summary(est)library(modsem) library(lavaan) m1 <- ' # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' syntax <- get_pi_syntax(m1) data <- get_pi_data(m1, oneInt) est <- sem(syntax, data) summary(est)
Check if model object has interaction terms
is_interaction_model(object)is_interaction_model(object)
object |
An object of class |
Logical. TRUE if the model has an interaction term,
otherwise it returns FALSE.
m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' est_dca <- modsem(m1, oneInt, method = "dblcent") is_interaction_model(est_dca) ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") is_interaction_model(est_lms) ## End(Not run)m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' est_dca <- modsem(m1, oneInt, method = "dblcent") is_interaction_model(est_dca) ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") is_interaction_model(est_lms) ## End(Not run)
The data stem from the large-scale assessment study PISA 2006 (Organisation for Economic Co-Operation and Development, 2009) where competencies of 15-year-old students in reading, mathematics, and science are assessed using nationally representative samples in 3-year cycles. In this example, data from the student background questionnaire from the Jordan sample of PISA 2006 were used. Only data of students with complete responses to all 15 items (N = 6,038) were considered.
A data frame of fifteen variables and 6,038 observations:
indicator for enjoyment of science, item ST16Q01: I generally have fun when I am learning <broad science> topics.
indicator for enjoyment of science, item ST16Q02: I like reading about <broad science>.
indicator for enjoyment of science, item ST16Q03: I am happy doing <broad science> problems.
indicator for enjoyment of science, item ST16Q04: I enjoy acquiring new knowledge in <broad science>.
indicator for enjoyment of science, item ST16Q05: I am interested in learning about <broad science>.
indicator for academic self-concept in science, item ST37Q01: I can easily understand new ideas in <school science>.
indicator for academic self-concept in science, item ST37Q02: Learning advanced <school science> topics would be easy for me.
indicator for academic self-concept in science, item ST37Q03: I can usually give good answers to <test questions> on <school science> topics.
indicator for academic self-concept in science, item ST37Q04: I learn <school science> topics quickly.
indicator for academic self-concept in science, item ST37Q05: <School science> topics are easy for me.
indicator for academic self-concept in science, item ST37Q06: When I am being taught <school science>, I can understand the concepts very well.
indicator for career aspirations in science, item ST29Q01: I would like to work in a career involving <broad science>.
indicator for career aspirations in science, item ST29Q02: I would like to study <broad science> after <secondary school>.
indicator for career aspirations in science, item ST29Q03: I would like to spend my life doing advanced <broad science>.
indicator for career aspirations in science, item ST29Q04: I would like to work on <broad science> projects as an adult.
This version of the dataset, as well as the description was gathered from the documentation of the 'nlsem' package (https://cran.r-project.org/package=nlsem), where the only difference is that the names of the variables were changed
Originally the dataset was gathered by the Organisation for Economic Co-Operation and Development (2009). Pisa 2006: Science competencies for tomorrow's world (Tech. Rep.). Paris, France. Obtained from: https://www.oecd.org/pisa/pisaproducts/database-pisa2006.htm
## Not run: m1 <- " ENJ =~ enjoy1 + enjoy2 + enjoy3 + enjoy4 + enjoy5 CAREER =~ career1 + career2 + career3 + career4 SC =~ academic1 + academic2 + academic3 + academic4 + academic5 + academic6 CAREER ~ ENJ + SC + ENJ:ENJ + SC:SC + ENJ:SC " est <- modsem(m1, data = jordan, method = "qml") summary(est) ## End(Not run)## Not run: m1 <- " ENJ =~ enjoy1 + enjoy2 + enjoy3 + enjoy4 + enjoy5 CAREER =~ career1 + career2 + career3 + career4 SC =~ academic1 + academic2 + academic3 + academic4 + academic5 + academic6 CAREER ~ ENJ + SC + ENJ:ENJ + SC:SC + ENJ:SC " est <- modsem(m1, data = jordan, method = "qml") summary(est) ## End(Not run)
modsem() is a function for estimating interaction effects between latent variables
in structural equation models (SEMs).
Methods for estimating interaction effects in SEMs can basically be split into two frameworks:
Product Indicator (PI) based approaches ("dblcent", "rca", "uca", "ca", "pind")
Distributionally (DA) based approaches ("lms", "qml").
For the product indicator-based approaches, modsem() is essentially a fancy wrapper for lavaan::sem() which generates the
necessary syntax and variables for the estimation of models with latent product indicators.
The distributionally based approaches are implemented separately and are
not estimated using lavaan::sem(), but rather using custom functions (largely
written in C++ for performance reasons). For greater control, it is advised that
you use one of the sub-functions (modsem_pi, modsem_da, modsem_mplus) directly,
as passing additional arguments to them via modsem() can lead to unexpected behavior.
modsem(model.syntax = NULL, data = NULL, method = "dblcent", ...)modsem(model.syntax = NULL, data = NULL, method = "dblcent", ...)
model.syntax |
|
data |
dataframe |
method |
method to use:
|
... |
arguments passed to other functions depending on the method (see |
modsem object with class modsem_pi, modsem_da, or modsem_mplus
library(modsem) # For more examples, check README and/or GitHub. # One interaction m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' # Double centering approach est1 <- modsem(m1, oneInt) summary(est1) ## Not run: # The Constrained Approach est1_ca <- modsem(m1, oneInt, method = "ca") summary(est1_ca) # LMS approach est1_lms <- modsem(m1, oneInt, method = "lms") summary(est1_lms) # QML approach est1_qml <- modsem(m1, oneInt, method = "qml") summary(est1_qml) ## End(Not run) # Theory Of Planned Behavior tpb <- ' # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC ' # Double centering approach est_tpb <- modsem(tpb, data = TPB) summary(est_tpb) ## Not run: # The Constrained Approach est_tpb_ca <- modsem(tpb, data = TPB, method = "ca") summary(est_tpb_ca) # LMS approach est_tpb_lms <- modsem(tpb, data = TPB, method = "lms", nodes = 32) summary(est_tpb_lms) # QML approach est_tpb_qml <- modsem(tpb, data = TPB, method = "qml") summary(est_tpb_qml) ## End(Not run)library(modsem) # For more examples, check README and/or GitHub. # One interaction m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' # Double centering approach est1 <- modsem(m1, oneInt) summary(est1) ## Not run: # The Constrained Approach est1_ca <- modsem(m1, oneInt, method = "ca") summary(est1_ca) # LMS approach est1_lms <- modsem(m1, oneInt, method = "lms") summary(est1_lms) # QML approach est1_qml <- modsem(m1, oneInt, method = "qml") summary(est1_qml) ## End(Not run) # Theory Of Planned Behavior tpb <- ' # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC ' # Double centering approach est_tpb <- modsem(tpb, data = TPB) summary(est_tpb) ## Not run: # The Constrained Approach est_tpb_ca <- modsem(tpb, data = TPB, method = "ca") summary(est_tpb_ca) # LMS approach est_tpb_lms <- modsem(tpb, data = TPB, method = "lms", nodes = 32) summary(est_tpb_lms) # QML approach est_tpb_qml <- modsem(tpb, data = TPB, method = "qml") summary(est_tpb_qml) ## End(Not run)
wrapper for coef, to be used with modsem::modsem_coef, since
coef is not in the namespace of modsem, but stats.
modsem_coef(object, ...)modsem_coef(object, ...)
object |
fitted model to inspect |
... |
additional arguments |
modsem_da() is a function for estimating interaction effects between latent variables
in structural equation models (SEMs) using distributional analytic (DA) approaches.
Methods for estimating interaction effects in SEMs can basically be split into
two frameworks:
1. Product Indicator-based approaches ("dblcent", "rca", "uca",
"ca", "pind")
2. Distributionally based approaches ("lms", "qml").
modsem_da() handles the latter and can estimate models using both QML and LMS,
necessary syntax, and variables for the estimation of models with latent product indicators.
NOTE: Run default_settings_da to see default arguments.
modsem_da( model.syntax = NULL, data = NULL, group = NULL, method = "lms", verbose = NULL, optimize = NULL, nodes = NULL, missing = NULL, convergence.abs = NULL, convergence.rel = NULL, optimizer = NULL, center.data = NULL, standardize.data = NULL, standardize.out = NULL, standardize = NULL, mean.observed = NULL, cov.syntax = NULL, double = NULL, calc.se = NULL, FIM = NULL, EFIM.S = NULL, OFIM.hessian = NULL, EFIM.parametric = NULL, robust.se = NULL, R.max = NULL, max.iter = NULL, max.step = NULL, start = NULL, epsilon = NULL, quad.range = NULL, adaptive.quad = NULL, adaptive.frequency = NULL, adaptive.quad.tol = NULL, n.threads = NULL, algorithm = NULL, em.control = NULL, ordered = NULL, ordered.mc.reps = NULL, ordered.min.iter = 20L, ordered.max.iter = 250L, ordered.tol = 1e-04, ordered.rng.seed = NULL, ordered.fixed.seed = FALSE, ordered.polyak.juditsky = TRUE, ordered.pj.extrapolate = TRUE, ordered.se = c("delta", "penalized", "naive"), ordered.se.penalty = 0.25, ordered.delta.reps = NULL, ordered.delta.epsilon = 0.01, ordered.standardize = TRUE, cluster = NULL, cr1s = FALSE, sampling.weights = NULL, sampling.weights.normalization = NULL, rcs = FALSE, rcs.choose = NULL, rcs.scale.corrected = TRUE, orthogonal.x = NULL, orthogonal.y = NULL, auto.fix.first = NULL, auto.fix.single = NULL, auto.split.syntax = NULL, fix.composite.var = NULL, ... )modsem_da( model.syntax = NULL, data = NULL, group = NULL, method = "lms", verbose = NULL, optimize = NULL, nodes = NULL, missing = NULL, convergence.abs = NULL, convergence.rel = NULL, optimizer = NULL, center.data = NULL, standardize.data = NULL, standardize.out = NULL, standardize = NULL, mean.observed = NULL, cov.syntax = NULL, double = NULL, calc.se = NULL, FIM = NULL, EFIM.S = NULL, OFIM.hessian = NULL, EFIM.parametric = NULL, robust.se = NULL, R.max = NULL, max.iter = NULL, max.step = NULL, start = NULL, epsilon = NULL, quad.range = NULL, adaptive.quad = NULL, adaptive.frequency = NULL, adaptive.quad.tol = NULL, n.threads = NULL, algorithm = NULL, em.control = NULL, ordered = NULL, ordered.mc.reps = NULL, ordered.min.iter = 20L, ordered.max.iter = 250L, ordered.tol = 1e-04, ordered.rng.seed = NULL, ordered.fixed.seed = FALSE, ordered.polyak.juditsky = TRUE, ordered.pj.extrapolate = TRUE, ordered.se = c("delta", "penalized", "naive"), ordered.se.penalty = 0.25, ordered.delta.reps = NULL, ordered.delta.epsilon = 0.01, ordered.standardize = TRUE, cluster = NULL, cr1s = FALSE, sampling.weights = NULL, sampling.weights.normalization = NULL, rcs = FALSE, rcs.choose = NULL, rcs.scale.corrected = TRUE, orthogonal.x = NULL, orthogonal.y = NULL, auto.fix.first = NULL, auto.fix.single = NULL, auto.split.syntax = NULL, fix.composite.var = NULL, ... )
model.syntax |
|
data |
A dataframe with observed variables used in the model. |
group |
Character. A variable name in the data frame defining the groups in a multiple group analysis |
method |
method to use:
|
verbose |
should estimation progress be shown |
optimize |
should starting parameters be optimized |
nodes |
number of quadrature nodes (points of integration) used in |
missing |
How should missing values be handled? If |
convergence.abs |
Absolute convergence criterion. Lower values give better estimates but slower computation. Not relevant when using the QML approach. For the LMS approach the EM-algorithm stops whenever the relative or absolute convergence criterion is reached. |
convergence.rel |
Relative convergence criterion. Lower values give better estimates but slower computation. For the LMS approach the EM-algorithm stops whenever the relative or absolute convergence criterion is reached. |
optimizer |
optimizer to use, can be either |
center.data |
should data be centered before fitting model |
standardize.data |
should data be scaled before fitting model, will be overridden by
|
standardize.out |
should output be standardized (note will alter the relationships of parameter constraints since parameters are scaled unevenly, even if they have the same label). This does not alter the estimation of the model, only the output. NOTE: It is recommended that you estimate the model normally and then standardize the output using
|
standardize |
will standardize the data before fitting the model, remove the mean
structure of the observed variables, and standardize the output. Note that NOTE: It is recommended that you estimate the model normally and then standardize the output using
|
mean.observed |
should the mean structure of the observed variables be estimated?
This will be overridden by NOTE: Not recommended unless you know what you are doing. |
cov.syntax |
model syntax for implied covariance matrix of exogenous latent variables
(see |
double |
try to double the number of dimensions of integration used in LMS,
this will be extremely slow but should be more similar to |
calc.se |
should standard errors be computed? NOTE: If |
FIM |
should the Fisher information matrix be calculated using the observed or expected values? Must be either |
EFIM.S |
if the expected Fisher information matrix is computed, |
OFIM.hessian |
Logical. If Note, that the Hessian is not always positive definite, and is more computationally expensive to calculate. The OPG should always be positive definite, and a lot faster to compute. If the model is correctly specified, and the sample size is large, then the two should yield similar results, and switching to the OPG can save a lot of time. Note, that the required sample size depends on the complexity of the model. A large difference between Hessian and OPG suggests misspecification, and
|
EFIM.parametric |
should data for calculating the expected Fisher information matrix be
simulated parametrically (simulated based on the assumptions and implied parameters
from the model), or non-parametrically (stochastically sampled)? If you believe that
normality assumptions are violated, |
robust.se |
should robust standard errors be computed, using the sandwich estimator? |
R.max |
Maximum population size (not sample size) used in the calculated of the expected fischer information matrix. |
max.iter |
maximum number of iterations. |
max.step |
maximum steps for the M-step in the EM algorithm (LMS). |
start |
starting parameters. |
epsilon |
finite difference for numerical derivatives. |
quad.range |
range in z-scores to perform numerical integration in LMS using,
when using quasi-adaptive Gaussian-Hermite Quadratures. By default |
adaptive.quad |
should a quasi adaptive quadrature be used? If |
adaptive.frequency |
How often should the quasi-adaptive quadrature be calculated? Defaults to 3, meaning that it is recalculated every third EM-iteration. |
adaptive.quad.tol |
Relative error tolerance for quasi adaptive quadrature. Defaults to |
n.threads |
number of threads to use for parallel processing. If |
algorithm |
algorithm to use for the EM algorithm. Can be either |
em.control |
a list of control parameters for the EM algorithm. See |
ordered |
Variables to be treated as ordered. Ordered indicators are handled with a Monte-Carlo correction for the LMS/QML estimator on standardized category scores. The fitted model is used to repeatedly simulate continuous indicators, ordinalize them to the observed cumulative category proportions, refit the standardized LMS/QML working model, and solve the resulting fixed-point problem. This follows the same general Monte-Carlo consistency logic as the MC-OrdPLSc algorithm described by Slupphaug, Mehmetoglu, and Mittner (2026, doi:10.31234/osf.io/fwzj6_v1). Thresholds are currently treated as fixed calibration quantities derived from the observed marginal category proportions. They are reported in the output for transparency, but they are not part of the free Monte-Carlo state vector. |
ordered.mc.reps |
Integer. Monte-Carlo sample size used in each ordered MC correction step. Larger values reduce simulation noise but increase runtime. |
ordered.min.iter |
Integer. Minimum number of Robbins-Monro iterations for the ordered MC correction. |
ordered.max.iter |
Integer. Maximum number of Robbins-Monro iterations for the ordered MC correction. |
ordered.tol |
Convergence tolerance for the ordered MC Robbins-Monro updates. |
ordered.rng.seed |
Optional integer random seed used by the ordered MC correction. |
ordered.fixed.seed |
Logical. If |
ordered.polyak.juditsky |
Logical. Should Polyak-Juditsky averaging be used in the ordered MC Robbins-Monro solver? |
ordered.pj.extrapolate |
Logical. If |
ordered.se |
Character string selecting the ordered MC standard-error correction.
|
ordered.se.penalty |
Non-negative numeric multiplier used when
|
ordered.delta.reps |
Integer. Monte-Carlo sample size used when approximating
the ordered MC delta-method Jacobian. Only relevant if
|
ordered.delta.epsilon |
Finite-difference step size used for the ordered MC
delta-method Jacobian. Only relevant if |
ordered.standardize |
Logical. Should scored ordered indicators be standardized before the observed-data fit and after ordinalizing simulated indicators? This is recommended for numerical stability and is enabled by default. |
cluster |
Clusters used to compute standard errors robust to non-indepence of observations. Must be paired with
|
cr1s |
Logical; if |
sampling.weights |
A variable name in the data frame containing sampling weight information. Depending on the sampling.weights.normalization argument, these weights may be rescaled (or not) so that their sum equals the number of observations (total or per group) |
sampling.weights.normalization |
If |
rcs |
Should latent variable indicators be replaced with reliability-corrected
single item indicators instead? See |
rcs.choose |
Which latent variables should get their indicators replaced with
reliability-corrected single items? It is passed to |
rcs.scale.corrected |
Should reliability-corrected items be scale-corrected? If |
orthogonal.x |
If |
orthogonal.y |
If |
auto.fix.first |
If |
auto.fix.single |
If |
auto.split.syntax |
Should the model syntax automatically be split into a
linear and non-linear part? This is done by moving the structural model for
linear endogenous variables (used in interaction terms) into the |
fix.composite.var |
If |
... |
additional arguments to be passed to the estimation function. |
modsem_da object
Slupphaug, K., Mehmetoglu, M., and Mittner, M. (2026, March 21). Consistent Estimates from Biased Estimators: Monte-Carlo Consistent Partial Least Squares for Latent Interaction Models with Ordinal Indicators. PsyArXiv. doi:10.31234/osf.io/fwzj6_v1
library(modsem) # For more examples, check README and/or GitHub. # One interaction m1 <- " # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " ## Not run: # QML Approach est_qml <- modsem_da(m1, oneInt, method = "qml") summary(est_qml) # Theory Of Planned Behavior tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " # LMS Approach est_lms <- modsem_da(tpb, data = TPB, method = "lms") summary(est_lms) ## End(Not run)library(modsem) # For more examples, check README and/or GitHub. # One interaction m1 <- " # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " ## Not run: # QML Approach est_qml <- modsem_da(m1, oneInt, method = "qml") summary(est_qml) # Theory Of Planned Behavior tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " # LMS Approach est_lms <- modsem_da(tpb, data = TPB, method = "lms") summary(est_lms) ## End(Not run)
function used to inspect fitted object. Similar to lavaan::lavInspect
argument what decides what to inspect
modsem_inspect.modsem_da lets you pull lavaan-style matrices,
optimiser diagnostics, expected moments, or fit measures from a
modsem_da object.
modsem_inspect(object, what = NULL, ...) ## S3 method for class 'lavaan' modsem_inspect(object, what = "free", ...) ## S3 method for class 'modsem_da' modsem_inspect(object, what = NULL, ...) ## S3 method for class 'modsem_pi' modsem_inspect(object, what = "free", ...)modsem_inspect(object, what = NULL, ...) ## S3 method for class 'lavaan' modsem_inspect(object, what = "free", ...) ## S3 method for class 'modsem_da' modsem_inspect(object, what = NULL, ...) ## S3 method for class 'modsem_pi' modsem_inspect(object, what = "free", ...)
object |
A fitted object of class |
what |
Character scalar selecting what to return (see Details).
If |
... |
Passed straight to |
For modsem_pi objects, it is just a wrapper for lavaan::lavInspect.
For modsem_da objects an internal function is called, which takes different
keywords for the what argument.
Below is a list of possible values for the what argument,
organised in several sections. Keywords are case-sensitive.
Presets
"default"Everything in Sample information, Optimiser diagnostics
Parameter tables, Model matrices, and Expected-moment matrices except
the raw data slot
"coef"Coefficients and variance-covariance matrix of both free and constrained parameters (same as "coef.all").
"coef.all"Coefficients and variance-covariance matrix of both free and constrained parameters (same as "coef").
"coef.free"Coefficients and variance-covariance matrix of the free parameters.
"all"All items listed below, including data.
"matrices"The lavaan-style model matrices.
"optim"Only the items under Optimiser diagnostics
.
"fit"A list with fit.h0, fit.h1, comparative.fit
Sample information:
"N"Number of analysed rows (integer).
"ngroups"Number of groups in model (integer).
"group"Group variable in model (character).
"group.label"Group labels (character).
"ovs"Observed variables used in model (character).
Parameter estimates and standard errors:
"coefficients.free"Free parameter values.
"coefficients.all"Both free and constrained parameter values.
"vcov.free"Variance–covariance of free coefficients only.
"vcov.all"Variance–covariance of both free and constrained coefficients.
Optimiser diagnostics:
"coefficients.free"Free parameter values.
"vcov.free"Variance–covariance of free coefficients only.
"information"Fisher information matrix.
"loglik"Log-likelihood.
"iterations"Optimiser iteration count.
"convergence"TRUE/FALSE indicating whether the model converged.
Parameter tables:
"partable"Parameter table with estimated parameters.
"partable.input"Parsed model syntax.
Model matrices:
"lambda"Factor loadings.
"theta"Residual covariance matrix for indicators.
"wmat"Composite loading matrix for observed indicators, if present.
"tmat"Composite residual matrix for indicators, if present.
"psi"Residual covariance matrix for latent variables.
"beta"Structural regression matrix among latent variables.
"nu"Intercepts for observed variables.
"alpha"Intercepts for latent variables.
Model-implied matrices:
"cov.ov"Model-implied covariance of observed variables.
"cov.lv"Model-implied covariance of latent variables.
"cov.all"Joint covariance of observed + latent variables.
"cor.ov"Correlation counterpart of "cov.ov".
"cor.lv"Correlation counterpart of "cov.lv".
"cor.all"Correlation counterpart of "cov.all".
"mean.ov"Expected means of observed variables.
"mean.lv"Expected means of latent variables.
"mean.all"Joint mean vector.
R-squared and standardized residual variances:
"r2.all"R-squared values for both observed (i.e., indicators) and latent endogenous variables.
"r2.lv"R-squared values for latent endogenous variables.
"r2.ov"R-squared values for observed (i.e., indicators) variables.
"res.all"Standardized residuals (i.e., 1 - R^2) for both observed (i.e., indicators) and latent endogenous variables.
"res.lv"Standardized residuals (i.e., 1 - R^2) for latent endogenous variables.
"res.ov"Standardized residuals (i.e., 1 - R^2) for observed variables (i.e., indicators).
Interaction-specific caveats:
If the model contains an uncentred latent interaction term it is centred
internally before any cov.*, cor.*, or mean.* matrices are
calculated.
These matrices should not be used to compute fit-statistics (e.g., chi-square and RMSEA) if there is an interaction term in the model.
A named list with the extracted information. If a single piece of information is returned, it is returned as is; not as a named element in a list.
modsem_inspect(lavaan): Inspect a lavaan object
modsem_inspect(modsem_da): Inspect a modsem_da object
modsem_inspect(modsem_pi): Inspect a modsem_pi object
## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " est <- modsem(m1, oneInt, "lms") modsem_inspect(est) # everything except "data" modsem_inspect(est, what = "optim") modsem_inspect(est, what = "matrices") ## End(Not run)## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " est <- modsem(m1, oneInt, "lms") modsem_inspect(est) # everything except "data" modsem_inspect(est, what = "optim") modsem_inspect(est, what = "matrices") ## End(Not run)
modsem model using multiple imputationEstimate a modsem model using multiple imputation
modsem_mimpute( model.syntax, data, method = "lms", m = 25, verbose = interactive(), se = c("simple", "full"), ... )modsem_mimpute( model.syntax, data, method = "lms", m = 25, verbose = interactive(), se = c("simple", "full"), ... )
model.syntax |
|
data |
A dataframe with observed variables used in the model. |
method |
Method to use:
|
m |
Number of imputations to perform. More imputations will yield better estimates but can also be (a lot) slower. |
verbose |
Should progress be printed to the console? |
se |
How should corrected standard errors be computed? Alternatives are:
|
... |
Arguments passed to |
modsem_impute is currently only available for the DA approaches
(LMS and QML). It performs multiple imputation using Amelia::amelia
and returns aggregated coefficients from the multiple imputations, along with
corrected standard errors.
m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' oneInt2 <- oneInt set.seed(123) k <- 200 I <- sample(nrow(oneInt2), k, replace = TRUE) J <- sample(ncol(oneInt2), k, replace = TRUE) for (k_i in seq_along(I)) oneInt2[I[k_i], J[k_i]] <- NA ## Not run: est <- modsem_mimpute(m1, oneInt2, m = 25) summary(est) ## End(Not run)m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' oneInt2 <- oneInt set.seed(123) k <- 200 I <- sample(nrow(oneInt2), k, replace = TRUE) J <- sample(ncol(oneInt2), k, replace = TRUE) for (k_i in seq_along(I)) oneInt2[I[k_i], J[k_i]] <- NA ## Not run: est <- modsem_mimpute(m1, oneInt2, m = 25) summary(est) ## End(Not run)
Mplus
Estimation latent interactions through Mplus
modsem_mplus( model.syntax, data, estimator = "ml", cluster = NULL, type = ifelse(is.null(cluster), yes = "random", no = "complex"), algorithm = "integration", processors = 2, integration = 15, rcs = FALSE, rcs.choose = NULL, rcs.scale.corrected = TRUE, output.std = TRUE, categorical = NULL, ... )modsem_mplus( model.syntax, data, estimator = "ml", cluster = NULL, type = ifelse(is.null(cluster), yes = "random", no = "complex"), algorithm = "integration", processors = 2, integration = 15, rcs = FALSE, rcs.choose = NULL, rcs.scale.corrected = TRUE, output.std = TRUE, categorical = NULL, ... )
model.syntax |
lavaan/modsem syntax |
data |
dataset |
estimator |
estimator argument passed to |
cluster |
cluster argument passed to |
type |
type argument passed to |
algorithm |
algorithm argument passed to |
processors |
processors argument passed to |
integration |
integration argument passed to |
rcs |
Should latent variable indicators be replaced with reliability-corrected
single item indicators instead? See |
rcs.choose |
Which latent variables should get their indicators replaced with
reliability-corrected single items? It is passed to |
rcs.scale.corrected |
Should reliability-corrected items be scale-corrected? If |
output.std |
Should |
categorical |
categorical argument passed to |
... |
arguments passed to other functions |
modsem_mplus object
# Theory Of Planned Behavior m1 <- ' # Outer Model X =~ x1 + x2 Z =~ z1 + z2 Y =~ y1 + y2 # Inner model Y ~ X + Z + X:Z ' ## Not run: # Check if Mplus is installed run <- tryCatch({MplusAutomation::detectMplus(); TRUE}, error = \(e) FALSE) if (run) { est_mplus <- modsem_mplus(m1, data = oneInt) summary(est_mplus) } ## End(Not run)# Theory Of Planned Behavior m1 <- ' # Outer Model X =~ x1 + x2 Z =~ z1 + z2 Y =~ y1 + y2 # Inner model Y ~ X + Z + X:Z ' ## Not run: # Check if Mplus is installed run <- tryCatch({MplusAutomation::detectMplus(); TRUE}, error = \(e) FALSE) if (run) { est_mplus <- modsem_mplus(m1, data = oneInt) summary(est_mplus) } ## End(Not run)
wrapper for nobs, to be used with modsem::modsem_nobs, since
nobs is not in the namespace of modsem, but stats.
modsem_nobs(object, ...)modsem_nobs(object, ...)
object |
fitted model to inspect |
... |
additional arguments |
modsem_pi() is a function for estimating interaction effects between latent variables,
in structural equation models (SEMs), using product indicators.
Methods for estimating interaction effects in SEMs can basically be split into
two frameworks:
1. Product Indicator based approaches ("dblcent", "rca", "uca",
"ca", "pind"), and
2. Distributionally based approaches ("lms", "qml").
modsem_pi() is essentially a fancy wrapper for lavaan::sem() which generates the
necessary syntax and variables for the estimation of models with latent product indicators.
Use default_settings_pi() to get the default settings for the different methods.
modsem_pi( model.syntax = NULL, data = NULL, method = "dblcent", match = NULL, match.recycle = NULL, standardize.data = FALSE, center.data = FALSE, first.loading.fixed = FALSE, center.before = NULL, center.after = NULL, residuals.prods = NULL, residual.cov.syntax = NULL, constrained.prod.mean = NULL, constrained.loadings = NULL, constrained.var = NULL, res.cov.method = NULL, res.cov.across = NULL, composite.int.res.cov = FALSE, auto.scale = "none", auto.center = "none", estimator = "ML", group = NULL, cluster = NULL, run = TRUE, na.rm = FALSE, suppress.warnings.lavaan = FALSE, suppress.warnings.match = FALSE, rcs = FALSE, rcs.choose = NULL, rcs.res.cov.xz = rcs, rcs.mc.reps = 1e+05, rcs.scale.corrected = TRUE, LAVFUN = lavaan::sem, ... )modsem_pi( model.syntax = NULL, data = NULL, method = "dblcent", match = NULL, match.recycle = NULL, standardize.data = FALSE, center.data = FALSE, first.loading.fixed = FALSE, center.before = NULL, center.after = NULL, residuals.prods = NULL, residual.cov.syntax = NULL, constrained.prod.mean = NULL, constrained.loadings = NULL, constrained.var = NULL, res.cov.method = NULL, res.cov.across = NULL, composite.int.res.cov = FALSE, auto.scale = "none", auto.center = "none", estimator = "ML", group = NULL, cluster = NULL, run = TRUE, na.rm = FALSE, suppress.warnings.lavaan = FALSE, suppress.warnings.match = FALSE, rcs = FALSE, rcs.choose = NULL, rcs.res.cov.xz = rcs, rcs.mc.reps = 1e+05, rcs.scale.corrected = TRUE, LAVFUN = lavaan::sem, ... )
model.syntax |
|
data |
dataframe |
method |
method to use:
|
match |
should the product indicators be created by using the match-strategy |
match.recycle |
should the indicators be recycled when using the match-strategy? I.e., if one of the latent variables have fewer indicators than the other, some indicators are recycled to match the latent variable with the most indicators. |
standardize.data |
should data be scaled before fitting model |
center.data |
should data be centered before fitting model |
first.loading.fixed |
Should the first factor loading in the latent product be fixed to one? Defaults to |
center.before |
should indicators in products be centered before computing products. |
center.after |
should indicator products be centered after they have been computed? |
residuals.prods |
should indicator products be centered using residuals. |
residual.cov.syntax |
should syntax for residual covariances be produced. |
constrained.prod.mean |
should syntax for product mean be produced. |
constrained.loadings |
should syntax for constrained loadings be produced. |
constrained.var |
should syntax for constrained variances be produced. |
res.cov.method |
method for constraining residual covariances. Options are
|
res.cov.across |
Should residual covariances be specified/freed across different interaction terms.
For example if you have two interaction terms |
composite.int.res.cov |
Should residual covariance syntax be generated for interaction
terms that are fully composite (i.e., all component variables defined with |
auto.scale |
methods which should be scaled automatically (usually not useful) |
auto.center |
methods which should be centered automatically (usually not useful) |
estimator |
estimator to use in |
group |
group variable for multigroup analysis |
cluster |
cluster variable for multilevel models |
run |
should the model be run via |
na.rm |
should missing values be removed (case-wise)? Defaults to FALSE. If |
suppress.warnings.lavaan |
should warnings from |
suppress.warnings.match |
should warnings from |
rcs |
Should latent variable indicators be replaced with reliability-corrected
single item indicators instead? See |
rcs.choose |
Which latent variables should get their indicators replaced with
reliability-corrected single items? It is passed to |
rcs.res.cov.xz |
Should the residual (co-)variances of the product indicators
created from the reliability-corrected single items (created if |
rcs.mc.reps |
Sample size used in monte-carlo simulation, when approximating the
the estimates of the residual (co-)variances between the product indicators formed
by reliabiliyt-corrected single items (see the |
rcs.scale.corrected |
Should reliability corrected items be scale-corrected? If |
LAVFUN |
Function used to estimate the model. Defaults to |
... |
arguments passed to |
modsem object
library(modsem) # For more examples, check README and/or GitHub. # One interaction m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' # Double centering approach est <- modsem_pi(m1, oneInt) summary(est) ## Not run: # The Constrained Approach est_ca <- modsem_pi(m1, oneInt, method = "ca") summary(est_ca) ## End(Not run) # Theory Of Planned Behavior tpb <- ' # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) # Covariances ATT ~~ SN + PBC PBC ~~ SN # Causal Relationships INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC ' # Double centering approach est_tpb <- modsem_pi(tpb, data = TPB) summary(est_tpb) ## Not run: # The Constrained Approach est_tpb_ca <- modsem_pi(tpb, data = TPB, method = "ca") summary(est_tpb_ca) ## End(Not run)library(modsem) # For more examples, check README and/or GitHub. # One interaction m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' # Double centering approach est <- modsem_pi(m1, oneInt) summary(est) ## Not run: # The Constrained Approach est_ca <- modsem_pi(m1, oneInt, method = "ca") summary(est_ca) ## End(Not run) # Theory Of Planned Behavior tpb <- ' # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) # Covariances ATT ~~ SN + PBC PBC ~~ SN # Causal Relationships INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC ' # Double centering approach est_tpb <- modsem_pi(tpb, data = TPB) summary(est_tpb) ## Not run: # The Constrained Approach est_tpb_ca <- modsem_pi(tpb, data = TPB, method = "ca") summary(est_tpb_ca) ## End(Not run)
modsem ModelsA generic function (and corresponding methods) that produces predicted
values or factor scores from modsem models.
modsem_predict(object, ...) ## S3 method for class 'modsem_pi' modsem_predict(object, ...) ## S3 method for class 'modsem_da' modsem_predict( object, newdata = NULL, method = c("EBM", "ML", "Bartlett", "Regression"), type = c("lv", "ov", "all"), standardized = FALSE, se = FALSE, drop.list.single.group = TRUE, ... )modsem_predict(object, ...) ## S3 method for class 'modsem_pi' modsem_predict(object, ...) ## S3 method for class 'modsem_da' modsem_predict( object, newdata = NULL, method = c("EBM", "ML", "Bartlett", "Regression"), type = c("lv", "ov", "all"), standardized = FALSE, se = FALSE, drop.list.single.group = TRUE, ... )
object |
An object of class |
... |
Further arguments passed to |
newdata |
Optional |
method |
Character. Scoring method. One of |
type |
Character. Which scores to return: |
standardized |
Logical. If |
se |
Logical. If |
drop.list.single.group |
Logical. If |
* For modsem_pi: whatever lavaan::predict() returns,
which is usually a matrix of factor scores.
* For modsem_da: a numeric matrix with one row per
observation. Columns depend on type: latent variable scores
("lv"), model-implied observed-variable scores ("ov"), or
both ("all"). Columns are optionally standardised if
standardized = TRUE.
modsem_predict(modsem_pi): Wrapper for lavaan::predict
modsem_predict(modsem_da): Computes factor scores or model-implied observed-variable scores for a
modsem_da model via MAP optimisation.
m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' est_dca <- modsem(m1, oneInt, method = "dblcent") head(modsem_predict(est_dca)) ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") head(modsem_predict(est_lms)) ## End(Not run)m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' est_dca <- modsem(m1, oneInt, method = "dblcent") head(modsem_predict(est_dca)) ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") head(modsem_predict(est_lms)) ## End(Not run)
wrapper for vcov, to be used with modsem::modsem_vcov, since
vcov is not in the namespace of modsem, but stats.
modsem_vcov(object, ...)modsem_vcov(object, ...)
object |
fitted model to inspect |
... |
additional arguments |
lavaan syntaxGenerate parameter table for lavaan syntax
modsemify(syntax, parentheses.as.string = FALSE)modsemify(syntax, parentheses.as.string = FALSE)
syntax |
model syntax |
parentheses.as.string |
Should parentheses be read parsed as literal strings? |
data.frame with columns lhs, op, rhs, mod
library(modsem) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' modsemify(m1)library(modsem) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' modsemify(m1)
A simulated dataset based on the elementary interaction model.
m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est <- modsem(m1, data = oneInt) summary(est)m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est <- modsem(m1, data = oneInt) summary(est)
Extract parameterEstimates from an estimated model
parameter_estimates(object, ...) ## S3 method for class 'lavaan' parameter_estimates( object, colon.pi = NULL, high.order.as.measr = NULL, rm.tmp.ov = NULL, label.renamed.prod = NULL, is.public = NULL, ... ) ## S3 method for class 'modsem_da' parameter_estimates( object, high.order.as.measr = TRUE, is.public = TRUE, rm.tmp.ov = is.public, label.renamed.prod = NULL, ... ) ## S3 method for class 'modsem_mplus' parameter_estimates( object, colon.pi = NULL, high.order.as.measr = NULL, rm.tmp.ov = NULL, label.renamed.prod = NULL, is.public = NULL, ... ) ## S3 method for class 'modsem_pi' parameter_estimates( object, colon.pi = FALSE, label.renamed.prod = FALSE, high.order.as.measr = NULL, rm.tmp.ov = NULL, is.public = NULL, ... )parameter_estimates(object, ...) ## S3 method for class 'lavaan' parameter_estimates( object, colon.pi = NULL, high.order.as.measr = NULL, rm.tmp.ov = NULL, label.renamed.prod = NULL, is.public = NULL, ... ) ## S3 method for class 'modsem_da' parameter_estimates( object, high.order.as.measr = TRUE, is.public = TRUE, rm.tmp.ov = is.public, label.renamed.prod = NULL, ... ) ## S3 method for class 'modsem_mplus' parameter_estimates( object, colon.pi = NULL, high.order.as.measr = NULL, rm.tmp.ov = NULL, label.renamed.prod = NULL, is.public = NULL, ... ) ## S3 method for class 'modsem_pi' parameter_estimates( object, colon.pi = FALSE, label.renamed.prod = FALSE, high.order.as.measr = NULL, rm.tmp.ov = NULL, is.public = NULL, ... )
object |
An object of class |
... |
Additional arguments passed to other functions |
colon.pi |
Should colons ( |
high.order.as.measr |
Should higher order measurement model be
denoted with the |
rm.tmp.ov |
Should temporary (hidden) variables be removed? |
label.renamed.prod |
Should renamed product terms keep their old (implicit) labels? |
is.public |
Should public version of parameter table be returned?
If |
parameter_estimates(lavaan): Get parameter estimates of a lavaan object
parameter_estimates(modsem_da): Get parameter estimates of a modsem_da object
parameter_estimates(modsem_mplus): Get parameter estimates of a modsem_mplus object
parameter_estimates(modsem_pi): Get parameter estimates of a modsem_pi object
m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' # Double centering approach est_dca <- modsem(m1, oneInt) pars <- parameter_estimates(est_dca) # no correction # Pretty summary summarize_partable(pars) # Only print the data.frame parsm1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' # Double centering approach est_dca <- modsem(m1, oneInt) pars <- parameter_estimates(est_dca) # no correction # Pretty summary summarize_partable(pars) # Only print the data.frame pars
This function creates an interaction plot of the outcome variable (y) as a function
of a focal predictor (x) at multiple values of a moderator (z). It is
designed for use with structural equation modeling (SEM) objects (e.g., those from
modsem). Predicted means (or predicted individual values) are calculated
via simple_slopes, and then plotted with ggplot2 to display
multiple regression lines and confidence/prediction bands.
plot_interaction( x, z, y, model, vals_x = seq(-3, 3, 0.001), vals_z, alpha_se = 0.15, digits = 2, ci_width = 0.95, ci_type = "confidence", rescale = TRUE, standardized = FALSE, xz = NULL, greyscale = FALSE, ... )plot_interaction( x, z, y, model, vals_x = seq(-3, 3, 0.001), vals_z, alpha_se = 0.15, digits = 2, ci_width = 0.95, ci_type = "confidence", rescale = TRUE, standardized = FALSE, xz = NULL, greyscale = FALSE, ... )
x |
A character string specifying the focal predictor (x-axis variable). |
z |
A character string specifying the moderator variable. |
y |
A character string specifying the outcome (dependent) variable. |
model |
An object of class |
vals_x |
A numeric vector of values at which to compute and plot the focal
predictor |
vals_z |
A numeric vector of values of the moderator |
alpha_se |
A numeric value in |
digits |
An integer specifying the number of decimal places to which the
moderator values ( |
ci_width |
A numeric value in |
ci_type |
A character string specifying whether to compute
|
rescale |
Logical. If |
standardized |
Should coefficients be standardized beforehand? |
xz |
A character string specifying the interaction term ( |
greyscale |
Logical. If |
... |
Additional arguments passed on to |
Computation Steps:
Calls simple_slopes to compute the predicted values of y
at the specified grid of x and z values.
Groups the resulting predictions by unique z-values (rounded to
digits) to create colored lines.
Plots these lines using ggplot2, adding ribbons for confidence
(or prediction) intervals, with transparency controlled by alpha_se.
Interpretation:
Each line in the plot corresponds to the regression of y on x at
a given level of z. The shaded region around each line (ribbon) shows
either the confidence interval for the predicted mean (if ci_type =
"confidence") or the prediction interval for individual observations (if
ci_type = "prediction"). Where the ribbons do not overlap, there is
evidence that the lines differ significantly over that range of x.
A ggplot object that can be further customized (e.g., with
additional + theme(...) layers). By default, it shows lines for each
moderator value and a shaded region corresponding to the interval type
(confidence or prediction).
## Not run: library(modsem) # Example 1: Interaction of X and Z in a simple SEM m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est1 <- modsem(m1, data = oneInt) # Plot interaction using a moderate range of X and two values of Z plot_interaction(x = "X", z = "Z", y = "Y", xz = "X:Z", vals_x = -3:3, vals_z = c(-0.2, 0), model = est1) # Example 2: Interaction in a theory-of-planned-behavior-style model tpb <- " # Outer Model ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ PBC:INT " est2 <- modsem(tpb, data = TPB, method = "lms", nodes = 32) # Plot with custom Z values and a denser X grid plot_interaction(x = "INT", z = "PBC", y = "BEH", xz = "PBC:INT", vals_x = seq(-3, 3, 0.01), vals_z = c(-0.5, 0.5), model = est2) ## End(Not run)## Not run: library(modsem) # Example 1: Interaction of X and Z in a simple SEM m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est1 <- modsem(m1, data = oneInt) # Plot interaction using a moderate range of X and two values of Z plot_interaction(x = "X", z = "Z", y = "Y", xz = "X:Z", vals_x = -3:3, vals_z = c(-0.2, 0), model = est1) # Example 2: Interaction in a theory-of-planned-behavior-style model tpb <- " # Outer Model ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ PBC:INT " est2 <- modsem(tpb, data = TPB, method = "lms", nodes = 32) # Plot with custom Z values and a denser X grid plot_interaction(x = "INT", z = "PBC", y = "BEH", xz = "PBC:INT", vals_x = seq(-3, 3, 0.01), vals_z = c(-0.5, 0.5), model = est2) ## End(Not run)
This function plots the simple slopes of an interaction effect across different values of a moderator variable using the Johnson-Neyman technique. It identifies regions where the effect of the predictor on the outcome is statistically significant.
plot_jn( x, z, y, model, min_z = -3, max_z = 3, sig.level = 0.05, alpha = 0.2, detail = 1000, sd.line = 2, standardized = FALSE, xz = NULL, greyscale = FALSE, plot.jn.points = TRUE, type = c("direct", "indirect", "total"), mc.quantiles = FALSE, mc.reps = 10000, ... )plot_jn( x, z, y, model, min_z = -3, max_z = 3, sig.level = 0.05, alpha = 0.2, detail = 1000, sd.line = 2, standardized = FALSE, xz = NULL, greyscale = FALSE, plot.jn.points = TRUE, type = c("direct", "indirect", "total"), mc.quantiles = FALSE, mc.reps = 10000, ... )
x |
The name of the predictor variable (as a character string). |
z |
The name of the moderator variable (as a character string). |
y |
The name of the outcome variable (as a character string). |
model |
A fitted model object of class |
min_z |
The minimum value of the moderator variable |
max_z |
The maximum value of the moderator variable |
sig.level |
The alpha-criterion for the confidence intervals (default is 0.05). |
alpha |
alpha setting used in |
detail |
The number of generated data points to use for the plot (default is 1000). You can increase this value for smoother plots. |
sd.line |
A thick black line showing |
standardized |
Should coefficients be standardized beforehand? |
xz |
The name of the interaction term. If not specified, it will be created using |
greyscale |
Logical. If |
plot.jn.points |
Logical. If |
type |
Which effect to display. One of |
mc.quantiles |
Should JN quantiles be calculated using Monte-Carlo estimates? |
mc.reps |
Number of Monte Carlo replicates used to approximate the confidence
bands when |
... |
Additional arguments (currently not used). |
The function calculates the simple slopes of the predictor variable x on the outcome variable y at different levels of the moderator variable z. It uses the Johnson-Neyman technique to identify the regions of z where the effect of x on y is statistically significant.
When plotting indirect or total effects, the function relies on Monte Carlo draws from the estimated sampling distribution of the parameters to approximate the conditional effect and its confidence interval across the moderator range.
It extracts the necessary coefficients and variance-covariance information from the fitted model object. The function then computes the critical t-value and solves the quadratic equation derived from the t-statistic equation to find the Johnson-Neyman points.
The plot displays:
The estimated simple slopes across the range of z.
Confidence intervals around the slopes.
Regions where the effect is significant (shaded areas).
Vertical dashed lines indicating the Johnson-Neyman points.
Text annotations providing the exact values of the Johnson-Neyman points.
A ggplot object showing the interaction plot with regions of significance.
## Not run: library(modsem) m1 <- ' visual =~ x1 + x2 + x3 textual =~ x4 + x5 + x6 speed =~ x7 + x8 + x9 visual ~ speed + textual + speed:textual ' est <- modsem(m1, data = lavaan::HolzingerSwineford1939, method = "ca") plot_jn(x = "speed", z = "textual", y = "visual", model = est, max_z = 6) ## End(Not run)## Not run: library(modsem) m1 <- ' visual =~ x1 + x2 + x3 textual =~ x4 + x5 + x6 speed =~ x7 + x8 + x9 visual ~ speed + textual + speed:textual ' est <- modsem(m1, data = lavaan::HolzingerSwineford1939, method = "ca") plot_jn(x = "speed", z = "textual", y = "visual", model = est, max_z = 6) ## End(Not run)
Generates a 3D surface plot to visualize the interaction effect of two variables (x and z)
on an outcome (y)
using parameter estimates from a supported model object (e.g., lavaan or modsem).
The function allows specifying ranges for x and z in standardized z-scores, which are then transformed
back to the original scale based on their means and standard deviations.
plot_surface( x, z, y, model, min_x = -3, max_x = 3, min_z = -3, max_z = 3, standardized = FALSE, detail = 0.01, xz = NULL, colorscale = "Viridis", reversescale = FALSE, showscale = TRUE, cmin = NULL, cmax = NULL, surface_opacity = 1, grid = FALSE, grid_nx = 12, grid_ny = 12, grid_color = "rgba(0,0,0,0.45)", group = NULL, ... )plot_surface( x, z, y, model, min_x = -3, max_x = 3, min_z = -3, max_z = 3, standardized = FALSE, detail = 0.01, xz = NULL, colorscale = "Viridis", reversescale = FALSE, showscale = TRUE, cmin = NULL, cmax = NULL, surface_opacity = 1, grid = FALSE, grid_nx = 12, grid_ny = 12, grid_color = "rgba(0,0,0,0.45)", group = NULL, ... )
x |
A character string specifying the name of the first predictor variable. |
z |
A character string specifying the name of the second predictor variable. |
y |
A character string specifying the name of the outcome variable. |
model |
A model object of class |
min_x |
Numeric. Minimum value of |
max_x |
Numeric. Maximum value of |
min_z |
Numeric. Minimum value of |
max_z |
Numeric. Maximum value of |
standardized |
Should coefficients be standardized beforehand? |
detail |
Numeric. Step size for the grid of |
xz |
Optional. A character string or vector specifying the interaction term between |
colorscale |
Character or list. Colorscale used to color the surface.
- Default is |
reversescale |
Logical. If |
showscale |
Logical. If |
cmin |
Numeric or |
cmax |
Numeric or |
surface_opacity |
Numeric (0–1). Controls the opacity of the surface.
- |
grid |
Logical. If |
grid_nx |
Integer. Approximate number of gridlines to draw along the
**x-axis** direction when |
grid_ny |
Integer. Approximate number of gridlines to draw along the
**y-axis** direction when |
grid_color |
Character. Color of the gridlines drawn on the surface.
Must be a valid CSS color string, including |
group |
Which group to create surface plot for. Only relevant for multigroup models. Must be an integer index, representing the nth group. |
... |
Additional arguments passed to |
The input min_x, max_x, min_z, and max_z define the range of x and z values in z-scores.
These are scaled by the standard deviations and shifted by the means of the respective variables, obtained
from the model parameter table. The resulting surface shows the predicted values of y over the grid of x and z.
The function supports models of class modsem (with subclasses modsem_pi, modsem_da, modsem_mplus) and lavaan.
For lavaan models, it is not designed for multigroup models, and a warning will be issued if multiple groups are detected.
A plotly surface plot object displaying the predicted values of y across the grid of x and z values.
The color bar shows the values of y.
The interaction term (xz) may need to be manually specified for some models. For non-lavaan models,
interaction terms may have their separator (:) removed based on circumstances.
m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner model Y ~ X + Z + X:Z " est1 <- modsem(m1, data = oneInt) plot_surface("X", "Z", "Y", model = est1) ## Not run: tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ PBC:INT " est2 <- modsem(tpb, TPB, method = "lms", nodes = 32) plot_surface(x = "INT", z = "PBC", y = "BEH", model = est2) ## End(Not run)m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner model Y ~ X + Z + X:Z " est1 <- modsem(m1, data = oneInt) plot_surface("X", "Z", "Y", model = est1) ## Not run: tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ PBC:INT " est2 <- modsem(tpb, TPB, method = "lms", nodes = 32) plot_surface(x = "INT", z = "PBC", y = "BEH", model = est2) ## End(Not run)
Replace (some of) the first‑order latent variables in a lavaan measurement
model by single composite indicators whose error variances are fixed from
Cronbach's . The function returns a modified lavaan model
syntax together with an augmented data set that contains the newly created
composite variables, so that you can fit the full SEM in a single step.
relcorr_single_item( syntax, data, choose = NULL, scale.corrected = TRUE, warn.lav = TRUE, group = NULL )relcorr_single_item( syntax, data, choose = NULL, scale.corrected = TRUE, warn.lav = TRUE, group = NULL )
syntax |
A character string containing lavaan model syntax. Must at
least include the measurement relations ( |
data |
A |
choose |
Optional. Character vector with the names of the latent
variables you wish to replace by single indicators. Defaults to all
first‑order latent variables in |
scale.corrected |
Should reliability-corrected items be scale-corrected? If |
warn.lav |
Should warnings from |
group |
Character. A variable name in the data frame defining the groups in a multiple group analysis |
The resulting object can be fed directly into modsem or lavaan::sem
by supplying syntax = $syntax and data = $data.
An object of S3 class ModsemRelcorr (a named list) with elements:
syntaxModified lavaan syntax string.
dataData frame with additional composite indicator columns.
parTableParameter table corresponding to 'syntax'.
reliabilityNamed numeric vector of reliabilities (one per latent variable).
AVENamed numeric vector with Average Variance Extracted values.
lVsCharacter vector of latent variables that were corrected.
single.itemsCharacter vector with names for the generated reliability corrected items
## Not run: tpb_uk <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att3 + att2 + att1 + att4 SN =~ sn4 + sn2 + sn3 + sn1 PBC =~ pbc2 + pbc1 + pbc3 + pbc4 INT =~ int2 + int1 + int3 + int4 BEH =~ beh3 + beh2 + beh1 + beh4 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " corrected <- relcorr_single_item(syntax = tpb_uk, data = TPB_UK) print(corrected) syntax <- corrected$syntax data <- corrected$data est_dca <- modsem(syntax, data = data, method = "dblcent") est_lms <- modsem(syntax, data = data, method="lms", nodes=32) summary(est_lms) ## End(Not run)## Not run: tpb_uk <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att3 + att2 + att1 + att4 SN =~ sn4 + sn2 + sn3 + sn1 PBC =~ pbc2 + pbc1 + pbc3 + pbc4 INT =~ int2 + int1 + int3 + int4 BEH =~ beh3 + beh2 + beh1 + beh4 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " corrected <- relcorr_single_item(syntax = tpb_uk, data = TPB_UK) print(corrected) syntax <- corrected$syntax data <- corrected$data est_dca <- modsem(syntax, data = data, method = "dblcent") est_lms <- modsem(syntax, data = data, method="lms", nodes=32) summary(est_lms) ## End(Not run)
modsem
All arguments are optional; omitted ones fall back to the defaults below.
Pass active = FALSE to turn highlighting off (and reset the palette).
set_modsem_colors( positive = "green3", negative = positive, true = "green3", false = "red", nan = "purple", na = "purple", inf = "purple", string = "cyan", active = TRUE )set_modsem_colors( positive = "green3", negative = positive, true = "green3", false = "red", nan = "purple", na = "purple", inf = "purple", string = "cyan", active = TRUE )
positive |
color of positive numbers. |
negative |
color of negative numbers. |
true |
color of |
false |
color of |
nan |
color of |
na |
color of |
inf |
color of |
string |
color of quoted strings. |
active |
Should color-theme be activated/deactived? |
TRUE if colors are active afterwards, otherwise FALSE.
set_modsem_colors(positive = "red3", negative = "red3", true = "darkgreen", false = "red3", na = "purple", string = "darkgreen") m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est <- modsem(m1, data = oneInt) colorize_output(summary(est)) colorize_output(est) # same as colorize_output(print(est)) colorize_output(modsem_inspect(est, what = "coef")) ## Not run: colorize_output(split = TRUE, { # Get live (uncolored) output # And print colored output at the end of execution est_lms <- modsem(m1, data = oneInt, method = "lms") summary(est_lms) }) colorize_output(modsem_inspect(est_lms)) ## End(Not run)set_modsem_colors(positive = "red3", negative = "red3", true = "darkgreen", false = "red3", na = "purple", string = "darkgreen") m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z " est <- modsem(m1, data = oneInt) colorize_output(summary(est)) colorize_output(est) # same as colorize_output(print(est)) colorize_output(modsem_inspect(est, what = "coef")) ## Not run: colorize_output(split = TRUE, { # Get live (uncolored) output # And print colored output at the end of execution est_lms <- modsem(m1, data = oneInt, method = "lms") summary(est_lms) }) colorize_output(modsem_inspect(est_lms)) ## End(Not run)
This function calculates simple slopes (predicted values of the outcome variable)
at user-specified values of the focal predictor (x) and moderator (z)
in a structural equation modeling (SEM) framework. It supports interaction terms
(xz), computes standard errors (SE), and optionally returns confidence or
prediction intervals for these predicted values. It also provides p-values for
hypothesis testing. This is useful for visualizing and interpreting moderation
effects or to see how the slope changes at different values of the moderator.
simple_slopes( x, z, y, model, vals_x = -3:3, vals_z = -1:1, rescale = TRUE, ci_width = 0.95, ci_type = "confidence", relative_h0 = TRUE, standardized = FALSE, xz = NULL, ... )simple_slopes( x, z, y, model, vals_x = -3:3, vals_z = -1:1, rescale = TRUE, ci_width = 0.95, ci_type = "confidence", relative_h0 = TRUE, standardized = FALSE, xz = NULL, ... )
x |
The name of the variable on the x-axis (focal predictor). |
z |
The name of the moderator variable. |
y |
The name of the outcome variable. |
model |
An object of class |
vals_x |
Numeric vector of values of |
vals_z |
Numeric vector of values of the moderator |
rescale |
Logical. If |
ci_width |
A numeric value between 0 and 1 indicating the confidence (or prediction) interval width. The default is 0.95 (i.e., 95% interval). |
ci_type |
A string indicating whether to compute a |
relative_h0 |
Logical. If |
standardized |
Should coefficients be standardized beforehand? |
xz |
The name of the interaction term ( |
... |
Additional arguments passed to lower-level functions or other internal helpers. |
Computation Steps
The function extracts parameter estimates (and, if necessary, their covariance
matrix) from the fitted SEM model (model).
It identifies the coefficients for x, z, and x:z in the model's
parameter table, as well as the variance of x, z and the residual variance
of y.
If xz is not provided, it will be constructed by combining x and
z with a colon (":"). Depending on the approach used to estimate the model,
the colon may be removed or replaced internally; the function attempts to reconcile that.
A grid of x and z values is created from vals_x and
vals_z. If rescale = TRUE, these values are transformed back into raw
metric units for display in the output.
For each point in the grid, a predicted value of y is computed via
(beta0 + beta_x * x + beta_z * z + beta_xz * x * z) and, if included, a
mean offset.
The standard error (std.error) is derived from the covariance matrix of
the relevant parameters, and if ci_type = "prediction", adds the residual
variance.
Confidence (or prediction) intervals are formed using ci_width (defaulting
to 95%). The result is a table-like data frame with predicted values, CIs,
standard errors, z-values, and p-values.
A data.frame (invisibly inheriting class "simple_slopes")
with columns:
vals_x, vals_z: The requested grid values of x and z.
predicted: The predicted value of y at that combination of
x and z.
std.error: The standard error of the predicted value.
z.value, p.value: The z-statistic and corresponding p-value
for testing the null hypothesis that predicted == h0.
ci.lower, ci.upper: Lower and upper bounds of the confidence
(or prediction) interval.
An attribute "variable_names" (list of x, z, y)
is attached for convenience.
## Not run: library(modsem) m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner model Y ~ X + Z + X:Z " est1 <- modsem(m1, data = oneInt) # Simple slopes at X in [-3, 3] and Z in [-1, 1], rescaled to the raw metric. simple_slopes(x = "X", z = "Z", y = "Y", model = est1) # If the data or user wants unscaled values, set rescale = FALSE, etc. simple_slopes(x = "X", z = "Z", y = "Y", model = est1, rescale = FALSE) ## End(Not run)## Not run: library(modsem) m1 <- " # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner model Y ~ X + Z + X:Z " est1 <- modsem(m1, data = oneInt) # Simple slopes at X in [-3, 3] and Z in [-1, 1], rescaled to the raw metric. simple_slopes(x = "X", z = "Z", y = "Y", model = est1) # If the data or user wants unscaled values, set rescale = FALSE, etc. simple_slopes(x = "X", z = "Z", y = "Y", model = est1, rescale = FALSE) ## End(Not run)
modsem_da modelstandardize_model() post-processes the output of
modsem_da() (or of modsem()) when method = "lms" /
method = "qml"), replacing the unstandardized coefficient vector
($coefs) and its variance–covariance matrix ($vcov) with fully
standardized counterparts (including the measurement model).The procedure is purely
algebraic— no re-estimation is carried out —and is therefore fast and
deterministic.
standardize_model(model, monte.carlo = FALSE, mc.reps = 10000, ...)standardize_model(model, monte.carlo = FALSE, mc.reps = 10000, ...)
model |
A fitted object of class |
monte.carlo |
Logical. If |
mc.reps |
Number of Monte Carlo replications. Default is 10,000.
Ignored if |
... |
Arguments passed on to other functions |
The same object (returned invisibly) with three slots overwritten
$parTableParameter table whose columns est and std.error
now hold standardized estimates and their (delta-method)
standard errors, as produced by standardized_estimates().
$coefsNamed numeric vector of standardized coefficients.
Intercepts (operator ~1) are removed, because a standardized
variable has mean 0 by definition.
$vcovVariance–covariance matrix corresponding to the updated coefficient vector. Rows/columns for intercepts are dropped, and the sub-matrix associated with rescaled parameters is adjusted so that its diagonal equals the squared standardized standard errors.
The object keeps its class attributes, allowing seamless use by downstream
S3 methods such as summary(), coef(), or vcov().
Because the function merely transforms existing estimates, parameter constraints imposed through shared labels remain satisfied.
standardized_estimates()Obtains the fully standardized parameter table used here.
modsem()Fit model using LMS or QML approaches.
modsem_da()Fit model using LMS or QML approaches.
## Not run: # Latent interaction estimated with LMS and standardized afterwards syntax <- " X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 Y ~ X + Z + X:Z " fit <- modsem_da(syntax, data = oneInt, method = "lms") sfit <- standardize_model(fit, monte.carlo = TRUE) # Compare unstandardized vs. standardized summaries summary(fit) # unstandardized summary(sfit) # standardized ## End(Not run)## Not run: # Latent interaction estimated with LMS and standardized afterwards syntax <- " X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 Y ~ X + Z + X:Z " fit <- modsem_da(syntax, data = oneInt, method = "lms") sfit <- standardize_model(fit, monte.carlo = TRUE) # Compare unstandardized vs. standardized summaries summary(fit) # unstandardized summary(sfit) # standardized ## End(Not run)
Computes standardized estimates of model parameters for various types of modsem objects.
standardized_estimates(object, ...) ## S3 method for class 'lavaan' standardized_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, ... ) ## S3 method for class 'modsem_da' standardized_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, rm.tmp.ov = TRUE, ... ) ## S3 method for class 'modsem_mplus' standardized_estimates(object, type = "stdyx", mc.reps = 1e+06, ...) ## S3 method for class 'modsem_pi' standardized_estimates( object, correction = FALSE, std.errors = c("rescale", "delta", "monte.carlo"), mc.reps = 10000, colon.pi = FALSE, ... )standardized_estimates(object, ...) ## S3 method for class 'lavaan' standardized_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, ... ) ## S3 method for class 'modsem_da' standardized_estimates( object, monte.carlo = FALSE, mc.reps = 10000, tolerance.zero = 1e-10, rm.tmp.ov = TRUE, ... ) ## S3 method for class 'modsem_mplus' standardized_estimates(object, type = "stdyx", mc.reps = 1e+06, ...) ## S3 method for class 'modsem_pi' standardized_estimates( object, correction = FALSE, std.errors = c("rescale", "delta", "monte.carlo"), mc.reps = 10000, colon.pi = FALSE, ... )
object |
An object of class |
... |
Additional arguments passed on to |
monte.carlo |
Logical. If |
mc.reps |
Integer. Number of Monte Carlo replications to use if |
tolerance.zero |
Threshold below which standard errors are set to |
rm.tmp.ov |
Should temporary (hidden) variables be removed? |
type |
Type of standardized estimates to retrieve. Can be one of: |
correction |
Logical. Whether to apply a correction to the standardized estimates
of the interaction term. By default, Hence the scale of the interaction effect changes, such that
the standardized interaction term does not correspond to one (standardized) unit
change in the moderating variables. If |
std.errors |
Character string indicating the method used to compute standard errors
when
Ignored if |
colon.pi |
Logical. If |
Standard errors can either be calculated using the delta method, or a monte.carlo simulation
(monte.carlo is not available for modsem_pi objects if correction == FALSE.).
NOTE that the standard errors of the standardized paramters change the assumptions of the
model, and will in most cases yield different z and p-values, compared to the unstandardized solution.
In almost all cases, significance testing should be based on the unstandardized solution. Since,
the standardization process changes the model assumptions, it also changes what the p-statistics measure.
I.e., the test statistics for the standardized and unstandardized solutions belong to different sets of
hypothesis, which are not exactly equivalent to each other.
For modsem_da and modsem_mplus objects, the interaction term is not a formal
variable in the model and therefore lacks a defined variance. Under assumptions of normality
and zero-mean variables, the interaction variance is estimated as:
This means the standardized estimate for the interaction differs from approaches like
lavaan, which treats the interaction as a latent variable with unit variance.
For modsem_pi objects, the interaction term is standardized by default assuming
var(xz) = 1, but this can be overridden using the correction argument.
NOTE: Standardized estimates are always placed in the est column,
not est.std, regardless of model type.
A data.frame with standardized estimates in the est column.
standardized_estimates(lavaan): Method for lavaan objects
standardized_estimates(modsem_da): Method for modsem_da objects
standardized_estimates(modsem_mplus): Retrieve standardized estimates from modsem_mplus object.
standardized_estimates(modsem_pi): Method for modsem_pi objects
m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' # Double centering approach est_dca <- modsem(m1, oneInt) std1 <- standardized_estimates(est_dca) # no correction summarize_partable(std1) std2 <- standardized_estimates(est_dca, correction = TRUE) # apply correction summarize_partable(std2) ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") standardized_estimates(est_lms) # correction not relevant for lms ## End(Not run)m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' # Double centering approach est_dca <- modsem(m1, oneInt) std1 <- standardized_estimates(est_dca) # no correction summarize_partable(std1) std2 <- standardized_estimates(est_dca, correction = TRUE) # apply correction summarize_partable(std2) ## Not run: est_lms <- modsem(m1, oneInt, method = "lms") standardized_estimates(est_lms) # correction not relevant for lms ## End(Not run)
modsem model.Summarize a parameter table from a modsem model.
summarize_partable( parTable, scientific = FALSE, ci = FALSE, digits = 3, loadings = TRUE, regressions = TRUE, covariances = TRUE, intercepts = TRUE, variances = TRUE, thresholds = TRUE )summarize_partable( parTable, scientific = FALSE, ci = FALSE, digits = 3, loadings = TRUE, regressions = TRUE, covariances = TRUE, intercepts = TRUE, variances = TRUE, thresholds = TRUE )
parTable |
A parameter table, typically obtained from a |
scientific |
Logical, whether to print p-values in scientific notation. |
ci |
Logical, whether to include confidence intervals in the output. |
digits |
Integer, number of digits to round the estimates to (default is 3). |
loadings |
Logical, whether to include factor loadings in the output. |
regressions |
Logical, whether to include regression coefficients in the output. |
covariances |
Logical, whether to include covariance estimates in the output. |
intercepts |
Logical, whether to include intercepts in the output. |
variances |
Logical, whether to include variance estimates in the output. |
thresholds |
Logical, whether to include threshold estimates in the output. |
A summary object containing the parameter table and additional information.
m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' # Double centering approach est_dca <- modsem(m1, oneInt) std <- standardized_estimates(est_dca, correction = TRUE) summarize_partable(std)m1 <- ' # Outer Model X =~ x1 + x2 + x3 Z =~ z1 + z2 + z3 Y =~ y1 + y2 + y3 # Inner Model Y ~ X + Z + X:Z ' # Double centering approach est_dca <- modsem(m1, oneInt) std <- standardized_estimates(est_dca, correction = TRUE) summarize_partable(std)
summary for modsem objects
summary for modsem objects
summary for modsem objects
## S3 method for class 'modsem_da' summary( object, H0 = is_interaction_model(object), verbose = interactive(), r.squared = TRUE, fit = FALSE, adjusted.stat = FALSE, digits = 3, scientific = FALSE, ci = FALSE, standardized = FALSE, centered = FALSE, monte.carlo = FALSE, mc.reps = 10000, loadings = TRUE, regressions = TRUE, covariances = TRUE, intercepts = TRUE, variances = TRUE, thresholds = TRUE, var.interaction = FALSE, ... ) ## S3 method for class 'modsem_mplus' summary( object, scientific = FALSE, standardized = FALSE, ci = FALSE, digits = 3, loadings = TRUE, regressions = TRUE, covariances = TRUE, intercepts = TRUE, variances = TRUE, ... ) ## S3 method for class 'modsem_pi' summary( object, H0 = is_interaction_model(object), r.squared = TRUE, adjusted.stat = FALSE, digits = 3, scientific = FALSE, verbose = TRUE, ... )## S3 method for class 'modsem_da' summary( object, H0 = is_interaction_model(object), verbose = interactive(), r.squared = TRUE, fit = FALSE, adjusted.stat = FALSE, digits = 3, scientific = FALSE, ci = FALSE, standardized = FALSE, centered = FALSE, monte.carlo = FALSE, mc.reps = 10000, loadings = TRUE, regressions = TRUE, covariances = TRUE, intercepts = TRUE, variances = TRUE, thresholds = TRUE, var.interaction = FALSE, ... ) ## S3 method for class 'modsem_mplus' summary( object, scientific = FALSE, standardized = FALSE, ci = FALSE, digits = 3, loadings = TRUE, regressions = TRUE, covariances = TRUE, intercepts = TRUE, variances = TRUE, ... ) ## S3 method for class 'modsem_pi' summary( object, H0 = is_interaction_model(object), r.squared = TRUE, adjusted.stat = FALSE, digits = 3, scientific = FALSE, verbose = TRUE, ... )
object |
modsem object to summarized |
H0 |
Should the baseline model be estimated, and used to produce comparative fit? |
verbose |
Should messages be printed? |
r.squared |
Calculate R-squared. |
fit |
Print additional fit measures. |
adjusted.stat |
Should sample size corrected/adjustes AIC and BIC be reported? |
digits |
Number of digits for printed numerical values |
scientific |
Should scientific format be used for p-values? |
ci |
print confidence intervals |
standardized |
standardize estimates |
centered |
Print mean centered estimates. |
monte.carlo |
Should Monte Carlo bootstrapped standard errors be used? Only
relevant if |
mc.reps |
Number of Monte Carlo repetitions. Only relevant if |
loadings |
print loadings |
regressions |
print regressions |
covariances |
print covariances |
intercepts |
print intercepts |
variances |
print variances |
thresholds |
Print thresholds. |
var.interaction |
If FALSE variances for interaction terms will be removed from the output. |
... |
arguments passed to lavaan::summary() |
## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " est1 <- modsem(m1, oneInt, "qml") summary(est1, ci = TRUE, scientific = TRUE) ## End(Not run)## Not run: m1 <- " # Outer Model X =~ x1 + x2 + x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z " est1 <- modsem(m1, oneInt, "qml") summary(est1, ci = TRUE, scientific = TRUE) ## End(Not run)
A simulated dataset based on the Theory of Planned Behaviour
tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC + INT:PBC " est <- modsem(tpb, data = TPB) summary(est)tpb <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att1 + att2 + att3 + att4 + att5 SN =~ sn1 + sn2 PBC =~ pbc1 + pbc2 + pbc3 INT =~ int1 + int2 + int3 BEH =~ b1 + b2 # Inner Model (Based on Steinmetz et al., 2011) INT ~ ATT + SN + PBC BEH ~ INT + PBC + INT:PBC " est <- modsem(tpb, data = TPB) summary(est)
A simulated dataset based on the Theory of Planned Behaviour, where INT is a higher order construct of ATT, SN, and PBC.
tpb <- ' # First order constructs ATT =~ att1 + att2 + att3 SN =~ sn1 + sn2 + sn3 PBC =~ pbc1 + pbc2 + pbc3 BEH =~ b1 + b2 # Higher order constructs INT =~ ATT + PBC + SN # Higher order interaction INTxPBC =~ ATT:PBC + SN:PBC + PBC:PBC # Structural model BEH ~ PBC + INT + INTxPBC ' ## Not run: est_ca <- modsem(tpb, data = TPB_1SO, method = "ca") summary(est_ca) est_dblcent <- modsem(tpb, data = TPB_1SO, method = "dblcent") summary(est_dblcent) ## End(Not run)tpb <- ' # First order constructs ATT =~ att1 + att2 + att3 SN =~ sn1 + sn2 + sn3 PBC =~ pbc1 + pbc2 + pbc3 BEH =~ b1 + b2 # Higher order constructs INT =~ ATT + PBC + SN # Higher order interaction INTxPBC =~ ATT:PBC + SN:PBC + PBC:PBC # Structural model BEH ~ PBC + INT + INTxPBC ' ## Not run: est_ca <- modsem(tpb, data = TPB_1SO, method = "ca") summary(est_ca) est_dblcent <- modsem(tpb, data = TPB_1SO, method = "dblcent") summary(est_dblcent) ## End(Not run)
A simulated dataset based on the Theory of Planned Behaviour, where INT is a higher order construct of ATT and SN, and PBC is a higher order construct of PC and PB.
tpb <- ' # First order constructs ATT =~ att1 + att2 + att3 SN =~ sn1 + sn2 + sn3 PB =~ pb1 + pb2 + pb3 PC =~ pc1 + pc2 + pc3 BEH =~ b1 + b2 # Higher order constructs INT =~ ATT + SN PBC =~ PC + PB # Higher order interaction INTxPBC =~ ATT:PC + ATT:PB + SN:PC + SN:PB # Structural model BEH ~ PBC + INT + INTxPBC ' ## Not run: est <- modsem(tpb, data = TPB_2SO, method = "ca") summary(est) ## End(Not run)tpb <- ' # First order constructs ATT =~ att1 + att2 + att3 SN =~ sn1 + sn2 + sn3 PB =~ pb1 + pb2 + pb3 PC =~ pc1 + pc2 + pc3 BEH =~ b1 + b2 # Higher order constructs INT =~ ATT + SN PBC =~ PC + PB # Higher order interaction INTxPBC =~ ATT:PC + ATT:PB + SN:PC + SN:PB # Structural model BEH ~ PBC + INT + INTxPBC ' ## Not run: est <- modsem(tpb, data = TPB_2SO, method = "ca") summary(est) ## End(Not run)
A dataset based on the Theory of Planned Behaviour from a UK sample. 4 variables with high communality were selected for each latent variable (ATT, SN, PBC, INT, BEH), from two time points (t1 and t2).
Gathered from a replication study by Hagger et al. (2023).
Obtained from doi:10.23668/psycharchives.12187
tpb_uk <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att3 + att2 + att1 + att4 SN =~ sn4 + sn2 + sn3 + sn1 PBC =~ pbc2 + pbc1 + pbc3 + pbc4 INT =~ int2 + int1 + int3 + int4 BEH =~ beh3 + beh2 + beh1 + beh4 # Inner Model (Based on Steinmetz et al., 2011) # Causal Relationsships INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " est <- modsem(tpb_uk, data = TPB_UK) summary(est)tpb_uk <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att3 + att2 + att1 + att4 SN =~ sn4 + sn2 + sn3 + sn1 PBC =~ pbc2 + pbc1 + pbc3 + pbc4 INT =~ int2 + int1 + int3 + int4 BEH =~ beh3 + beh2 + beh1 + beh4 # Inner Model (Based on Steinmetz et al., 2011) # Causal Relationsships INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " est <- modsem(tpb_uk, data = TPB_UK) summary(est)
This function estimates the path from x to y using the path tracing rules.
Note that it only works with structural parameters, so "=~" are ignored, unless
measurement.model = TRUE.
If you want to use the measurement model,
"~" should be in the mod column of pt.
trace_path( pt, x, y, parenthesis = TRUE, missing.cov = FALSE, measurement.model = TRUE, maxlen = 100, paramCol = "mod", ... )trace_path( pt, x, y, parenthesis = TRUE, missing.cov = FALSE, measurement.model = TRUE, maxlen = 100, paramCol = "mod", ... )
pt |
A data frame with columns |
x |
Source variable |
y |
Destination variable |
parenthesis |
If |
missing.cov |
If |
measurement.model |
If |
maxlen |
Maximum length of a path before aborting |
paramCol |
The column name in |
... |
Additional arguments passed to trace_path |
A string with the estimated path (simplified if possible)
library(modsem) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' pt <- modsemify(m1) trace_path(pt, x = "Y", y = "Y", missing.cov = TRUE) # variance of Ylibrary(modsem) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' pt <- modsemify(m1) trace_path(pt, x = "Y", y = "Y", missing.cov = TRUE) # variance of Y
Estimate an interaction model using a twostep procedure. For the PI approaches, the lavaan::sam function
is used to optimize the models, instead of lavaan::sem. Note that the product indicators are still used,
and not the newly developed SAM approach to estimate latent interactions. For the DA approaches (LMS and QML)
the measurement model is estimated using a CFA (lavaan::cfa). The structural model is estimated using
modsem_da, where the estimates in the measurement model are fixed, based on the CFA estimates.
Note that standard errors are uncorrected (i.e., naive), and do not account for the uncertainty in the CFA estimates.
NOTE, this is an experimental feature!
twostep(model.syntax, data, method = "lms", ...)twostep(model.syntax, data, method = "lms", ...)
model.syntax |
|
data |
dataframe |
method |
method to use:
|
... |
arguments passed to other functions depending on the method (see |
modsem object with class modsem_pi or modsem_da.
library(modsem) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' est_dblcent <- twostep(m1, oneInt, method = "dblcent") summary(est_dblcent) ## Not run: est_lms <- twostep(m1, oneInt, method = "lms") summary(est_lms) est_qml <- twostep(m1, oneInt, method = "qml") summary(est_qml) ## End(Not run) tpb_uk <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att3 + att2 + att1 + att4 SN =~ sn4 + sn2 + sn3 + sn1 PBC =~ pbc2 + pbc1 + pbc3 + pbc4 INT =~ int2 + int1 + int3 + int4 BEH =~ beh3 + beh2 + beh1 + beh4 # Inner Model (Based on Steinmetz et al., 2011) # Causal Relationsships INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " uk_dblcent <- twostep(tpb_uk, TPB_UK, method = "dblcent") summary(uk_dblcent) ## Not run: uk_qml <- twostep(tpb_uk, TPB_UK, method = "qml") uk_lms <- twostep(tpb_uk, TPB_UK, method = "lms", nodes = 32, adaptive.quad = TRUE) summary(uk_lms) ## End(Not run)library(modsem) m1 <- ' # Outer Model X =~ x1 + x2 +x3 Y =~ y1 + y2 + y3 Z =~ z1 + z2 + z3 # Inner model Y ~ X + Z + X:Z ' est_dblcent <- twostep(m1, oneInt, method = "dblcent") summary(est_dblcent) ## Not run: est_lms <- twostep(m1, oneInt, method = "lms") summary(est_lms) est_qml <- twostep(m1, oneInt, method = "qml") summary(est_qml) ## End(Not run) tpb_uk <- " # Outer Model (Based on Hagger et al., 2007) ATT =~ att3 + att2 + att1 + att4 SN =~ sn4 + sn2 + sn3 + sn1 PBC =~ pbc2 + pbc1 + pbc3 + pbc4 INT =~ int2 + int1 + int3 + int4 BEH =~ beh3 + beh2 + beh1 + beh4 # Inner Model (Based on Steinmetz et al., 2011) # Causal Relationsships INT ~ ATT + SN + PBC BEH ~ INT + PBC BEH ~ INT:PBC " uk_dblcent <- twostep(tpb_uk, TPB_UK, method = "dblcent") summary(uk_dblcent) ## Not run: uk_qml <- twostep(tpb_uk, TPB_UK, method = "qml") uk_lms <- twostep(tpb_uk, TPB_UK, method = "lms", nodes = 32, adaptive.quad = TRUE) summary(uk_lms) ## End(Not run)
Extract or modify parTable from an estimated model with estimated variances of interaction terms
var_interactions(object, ...)var_interactions(object, ...)
object |
An object of class |
... |
Additional arguments passed to other functions |