LMS and QML approaches
lms_qml.Rmd
The Latent Moderated Structural Equations (LMS) and the Quasi Maximum Likelihood (QML) Approach
Both the LMS
and QML
approaches work on
most models, but interaction effects with endogenous variables can be
tricky to estimate (see the vignette).
Both approaches, particularly the LMS
approach, are
computationally intensive and are partially implemented in C++ (using
Rcpp
and RcppArmadillo
). Additionally,
starting parameters are estimated using the double-centering approach,
and the means of the observed variables are used to generate good
starting parameters for faster convergence. If you want to monitor the
progress of the estimation process, you can use
verbose = TRUE
.
A Simple Example
Here is an example of the LMS
approach for a simple
model. By default, the summary()
function calculates fit
measures compared to a null model (i.e., the same model without an
interaction term).
library(modsem)
m1 <- '
# Outer Model
X =~ x1 + x2 + x3
Z =~ z1 + z2 + z3
Y =~ y1 + y2 + y3
# Inner Model
Y ~ X + Z + X:Z
'
lms1 <- modsem(m1, oneInt, method = "lms")
# Standardized estimates
summary(lms1, standardized = TRUE)
#> Estimating baseline model (H0)
#>
#> modsem (version 1.0.11):
#>
#> Estimator LMS
#> Optimization method EMA-NLMINB
#> Number of observations 2000
#> Number of iterations 45
#> Loglikelihood -14687.69
#> Akaike (AIC) 29437.39
#> Bayesian (BIC) 29611.01
#>
#> Numerical Integration:
#> Points of integration (per dim) 24
#> Dimensions 1
#> Total points of integration 24
#>
#> Fit Measures for Baseline Model (H0):
#> Loglikelihood -17831.87
#> Akaike (AIC) 35723.75
#> Bayesian (BIC) 35891.78
#> Chi-square 17.52
#> Degrees of Freedom (Chi-square) 24
#> P-value (Chi-square) 0.826
#> RMSEA 0.000
#>
#> Comparative Fit to H0 (LRT test):
#> Loglikelihood change 3144.18
#> Difference test (D) 6288.36
#> Degrees of freedom (D) 1
#> P-value (D) 0.000
#>
#> R-Squared Interaction Model (H1):
#> Y 0.595
#> R-Squared Baseline Model (H0):
#> Y 0.395
#> R-Squared Change (H1 - H0):
#> Y 0.199
#>
#> Parameter Estimates:
#> Coefficients standardized
#> Information observed
#> Standard errors standard
#>
#> Latent Variables:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> X =~
#> x1 1.000 0.927
#> x2 0.804 0.012 64.32 0.000 0.891
#> x3 0.915 0.013 67.94 0.000 0.912
#> Z =~
#> z1 1.000 0.927
#> z2 0.810 0.012 65.09 0.000 0.898
#> z3 0.881 0.013 67.60 0.000 0.913
#> Y =~
#> y1 1.000 0.969
#> y2 0.798 0.007 107.55 0.000 0.954
#> y3 0.899 0.008 112.58 0.000 0.961
#>
#> Regressions:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> Y ~
#> X 0.672 0.031 21.71 0.000 0.425
#> Z 0.569 0.030 19.05 0.000 0.369
#> X:Z 0.713 0.028 25.72 0.000 0.455
#>
#> Intercepts:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> .x1 1.022 0.021 47.66 0.000
#> .x2 1.215 0.018 67.19 0.000
#> .x3 0.919 0.020 45.92 0.000
#> .z1 1.010 0.024 41.69 0.000
#> .z2 1.205 0.020 59.44 0.000
#> .z3 0.915 0.022 42.18 0.000
#> .y1 1.036 0.032 32.28 0.000
#> .y2 1.220 0.026 46.66 0.000
#> .y3 0.953 0.029 32.68 0.000
#>
#> Covariances:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> X ~~
#> Z 0.199 0.024 8.32 0.000 0.200
#>
#> Variances:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> .x1 0.160 0.008 19.30 0.000 0.142
#> .x2 0.163 0.007 23.88 0.000 0.206
#> .x3 0.165 0.008 21.23 0.000 0.169
#> .z1 0.166 0.009 18.47 0.000 0.141
#> .z2 0.160 0.007 22.67 0.000 0.193
#> .z3 0.158 0.008 20.80 0.000 0.167
#> .y1 0.160 0.009 18.01 0.000 0.062
#> .y2 0.154 0.007 22.68 0.000 0.091
#> .y3 0.164 0.008 20.68 0.000 0.077
#> X 0.972 0.033 29.85 0.000 1.000
#> Z 1.017 0.038 26.95 0.000 1.000
#> .Y 0.984 0.038 26.00 0.000 0.405
Here is the same example using the QML
approach:
qml1 <- modsem(m1, oneInt, method = "qml")
summary(qml1)
#> Estimating baseline model (H0)
#>
#> modsem (version 1.0.11):
#>
#> Estimator QML
#> Optimization method NLMINB
#> Number of observations 2000
#> Number of iterations 106
#> Loglikelihood -17501.61
#> Akaike (AIC) 35065.21
#> Bayesian (BIC) 35238.84
#>
#> Fit Measures for Baseline Model (H0):
#> Loglikelihood -17831.87
#> Akaike (AIC) 35723.75
#> Bayesian (BIC) 35891.78
#> Chi-square 17.52
#> Degrees of Freedom (Chi-square) 24
#> P-value (Chi-square) 0.826
#> RMSEA 0.000
#>
#> Comparative Fit to H0 (LRT test):
#> Loglikelihood change 330.27
#> Difference test (D) 660.54
#> Degrees of freedom (D) 1
#> P-value (D) 0.000
#>
#> R-Squared Interaction Model (H1):
#> Y 0.617
#> R-Squared Baseline Model (H0):
#> Y 0.395
#> R-Squared Change (H1 - H0):
#> Y 0.222
#>
#> Parameter Estimates:
#> Coefficients unstandardized
#> Information observed
#> Standard errors standard
#>
#> Latent Variables:
#> Estimate Std.Error z.value P(>|z|)
#> X =~
#> x1 1.000
#> x2 0.803 0.013 63.96 0.000
#> x3 0.913 0.013 67.77 0.000
#> Z =~
#> z1 1.000
#> z2 0.810 0.012 65.15 0.000
#> z3 0.881 0.013 67.67 0.000
#> Y =~
#> y1 1.000
#> y2 0.798 0.007 107.56 0.000
#> y3 0.899 0.008 112.53 0.000
#>
#> Regressions:
#> Estimate Std.Error z.value P(>|z|)
#> Y ~
#> X 0.673 0.031 21.89 0.000
#> Z 0.566 0.030 18.82 0.000
#> X:Z 0.713 0.027 26.50 0.000
#>
#> Intercepts:
#> Estimate Std.Error z.value P(>|z|)
#> .x1 1.023 0.024 42.84 0.000
#> .x2 1.216 0.020 60.92 0.000
#> .x3 0.920 0.022 41.43 0.000
#> .z1 1.012 0.024 41.57 0.000
#> .z2 1.206 0.020 59.27 0.000
#> .z3 0.916 0.022 42.06 0.000
#> .y1 1.037 0.033 31.31 0.000
#> .y2 1.221 0.027 45.29 0.000
#> .y3 0.954 0.030 31.71 0.000
#>
#> Covariances:
#> Estimate Std.Error z.value P(>|z|)
#> X ~~
#> Z 0.200 0.024 8.24 0.000
#>
#> Variances:
#> Estimate Std.Error z.value P(>|z|)
#> .x1 0.158 0.009 18.12 0.000
#> .x2 0.162 0.007 23.18 0.000
#> .x3 0.165 0.008 20.83 0.000
#> .z1 0.166 0.009 18.46 0.000
#> .z2 0.159 0.007 22.70 0.000
#> .z3 0.158 0.008 20.81 0.000
#> .y1 0.159 0.009 17.98 0.000
#> .y2 0.154 0.007 22.66 0.000
#> .y3 0.164 0.008 20.69 0.000
#> X 0.983 0.036 26.99 0.000
#> Z 1.018 0.038 26.94 0.000
#> .Y 0.901 0.040 22.70 0.000
A More Complicated Example
Below is an example of a more complex model based on the theory of
planned behavior (TPB), which includes two endogenous variables and an
interaction between an endogenous and exogenous variable. When
estimating more complex models with the LMS
approach, it is
recommended to increase the number of nodes used for numerical
integration. By default, the number of nodes is set to 16, but this can
be increased using the nodes
argument. The
nodes
argument has no effect on the QML
approach.
When there is an interaction effect between an endogenous and
exogenous variable, it is recommended to use at least 32 nodes for the
LMS
approach. You can also obtain robust standard errors by
setting robust.se = TRUE
in the modsem()
function.
NOTE: If you want the LMS
approach to
produce results as similar as possible to Mplus
, you should
consider increasing the number of nodes using the nodes
argument, and or using a quasi-adaptive quadrature by setting
adaptive.quad=TRUE
.
# ATT = Attitude
# PBC = Perceived Behavioral Control
# INT = Intention
# SN = Subjective Norms
# BEH = 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
'
lms2 <- modsem(tpb, TPB, method = "lms", nodes = 32)
summary(lms2)
#> Estimating baseline model (H0)
#>
#> modsem (version 1.0.11):
#>
#> Estimator LMS
#> Optimization method EMA-NLMINB
#> Number of observations 2000
#> Number of iterations 34
#> Loglikelihood -23439.01
#> Akaike (AIC) 46986.02
#> Bayesian (BIC) 47288.47
#>
#> Numerical Integration:
#> Points of integration (per dim) 32
#> Dimensions 1
#> Total points of integration 32
#>
#> Fit Measures for Baseline Model (H0):
#> Loglikelihood -26393.22
#> Akaike (AIC) 52892.45
#> Bayesian (BIC) 53189.29
#> Chi-square 66.27
#> Degrees of Freedom (Chi-square) 82
#> P-value (Chi-square) 0.897
#> RMSEA 0.000
#>
#> Comparative Fit to H0 (LRT test):
#> Loglikelihood change 2954.21
#> Difference test (D) 5908.42
#> Degrees of freedom (D) 1
#> P-value (D) 0.000
#>
#> R-Squared Interaction Model (H1):
#> INT 0.364
#> BEH 0.259
#> R-Squared Baseline Model (H0):
#> INT 0.367
#> BEH 0.210
#> R-Squared Change (H1 - H0):
#> INT -0.003
#> BEH 0.049
#>
#> Parameter Estimates:
#> Coefficients unstandardized
#> Information observed
#> Standard errors standard
#>
#> Latent Variables:
#> Estimate Std.Error z.value P(>|z|)
#> PBC =~
#> pbc1 1.000
#> pbc2 0.914 0.013 69.42 0.000
#> pbc3 0.802 0.012 65.98 0.000
#> ATT =~
#> att1 1.000
#> att2 0.878 0.012 71.56 0.000
#> att3 0.789 0.012 66.38 0.000
#> att4 0.695 0.011 61.00 0.000
#> att5 0.887 0.013 70.85 0.000
#> SN =~
#> sn1 1.000
#> sn2 0.889 0.017 52.61 0.000
#> INT =~
#> int1 1.000
#> int2 0.913 0.015 59.05 0.000
#> int3 0.807 0.014 55.74 0.000
#> BEH =~
#> b1 1.000
#> b2 0.959 0.030 31.76 0.000
#>
#> Regressions:
#> Estimate Std.Error z.value P(>|z|)
#> INT ~
#> PBC 0.217 0.030 7.33 0.000
#> ATT 0.214 0.026 8.18 0.000
#> SN 0.176 0.028 6.38 0.000
#> BEH ~
#> PBC 0.233 0.022 10.39 0.000
#> INT 0.188 0.025 7.60 0.000
#> PBC:INT 0.205 0.018 11.30 0.000
#>
#> Intercepts:
#> Estimate Std.Error z.value P(>|z|)
#> .pbc1 0.991 0.024 41.26 0.000
#> .pbc2 0.979 0.022 43.77 0.000
#> .pbc3 0.986 0.020 49.22 0.000
#> .att1 1.009 0.024 41.37 0.000
#> .att2 1.002 0.022 46.30 0.000
#> .att3 1.012 0.020 50.77 0.000
#> .att4 0.995 0.018 54.97 0.000
#> .att5 0.987 0.022 45.02 0.000
#> .sn1 1.001 0.024 41.04 0.000
#> .sn2 1.006 0.022 46.05 0.000
#> .int1 1.010 0.022 46.51 0.000
#> .int2 1.009 0.020 49.94 0.000
#> .int3 1.002 0.018 54.34 0.000
#> .b1 0.999 0.021 46.80 0.000
#> .b2 1.017 0.020 50.88 0.000
#>
#> Covariances:
#> Estimate Std.Error z.value P(>|z|)
#> PBC ~~
#> ATT 0.668 0.028 23.51 0.000
#> SN 0.668 0.029 23.18 0.000
#> ATT ~~
#> SN 0.623 0.029 21.83 0.000
#>
#> Variances:
#> Estimate Std.Error z.value P(>|z|)
#> .pbc1 0.148 0.008 19.18 0.000
#> .pbc2 0.159 0.007 21.26 0.000
#> .pbc3 0.155 0.006 23.85 0.000
#> .att1 0.167 0.007 23.54 0.000
#> .att2 0.150 0.006 24.72 0.000
#> .att3 0.159 0.006 26.39 0.000
#> .att4 0.162 0.006 27.65 0.000
#> .att5 0.159 0.006 24.93 0.000
#> .sn1 0.178 0.015 12.12 0.000
#> .sn2 0.156 0.012 13.24 0.000
#> .int1 0.157 0.009 18.11 0.000
#> .int2 0.160 0.008 20.41 0.000
#> .int3 0.168 0.007 23.55 0.000
#> .b1 0.185 0.018 10.07 0.000
#> .b2 0.136 0.017 8.19 0.000
#> PBC 0.947 0.035 27.19 0.000
#> ATT 0.992 0.037 27.11 0.000
#> SN 0.981 0.039 25.38 0.000
#> .INT 0.491 0.020 24.65 0.000
#> .BEH 0.456 0.023 20.14 0.000
qml2 <- modsem(tpb, TPB, method = "qml")
summary(qml2, standardized = TRUE) # Standardized estimates
#> Estimating baseline model (H0)
#>
#> modsem (version 1.0.11):
#>
#> Estimator QML
#> Optimization method NLMINB
#> Number of observations 2000
#> Number of iterations 73
#> Loglikelihood -26326.25
#> Akaike (AIC) 52760.5
#> Bayesian (BIC) 53062.95
#>
#> Fit Measures for Baseline Model (H0):
#> Loglikelihood -26393.22
#> Akaike (AIC) 52892.45
#> Bayesian (BIC) 53189.29
#> Chi-square 66.27
#> Degrees of Freedom (Chi-square) 82
#> P-value (Chi-square) 0.897
#> RMSEA 0.000
#>
#> Comparative Fit to H0 (LRT test):
#> Loglikelihood change 66.97
#> Difference test (D) 133.95
#> Degrees of freedom (D) 1
#> P-value (D) 0.000
#>
#> R-Squared Interaction Model (H1):
#> INT 0.366
#> BEH 0.263
#> R-Squared Baseline Model (H0):
#> INT 0.367
#> BEH 0.210
#> R-Squared Change (H1 - H0):
#> INT 0.000
#> BEH 0.053
#>
#> Parameter Estimates:
#> Coefficients standardized
#> Information observed
#> Standard errors standard
#>
#> Latent Variables:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> PBC =~
#> pbc1 1.000 0.933
#> pbc2 0.912 0.013 69.47 0.000 0.913
#> pbc3 0.801 0.012 66.10 0.000 0.894
#> ATT =~
#> att1 1.000 0.925
#> att2 0.878 0.012 71.56 0.000 0.915
#> att3 0.789 0.012 66.37 0.000 0.892
#> att4 0.695 0.011 61.00 0.000 0.865
#> att5 0.887 0.013 70.85 0.000 0.912
#> SN =~
#> sn1 1.000 0.921
#> sn2 0.888 0.017 52.61 0.000 0.913
#> INT =~
#> int1 1.000 0.912
#> int2 0.913 0.015 59.05 0.000 0.895
#> int3 0.807 0.014 55.73 0.000 0.866
#> BEH =~
#> b1 1.000 0.877
#> b2 0.961 0.030 31.71 0.000 0.900
#>
#> Regressions:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> INT ~
#> PBC 0.218 0.030 7.35 0.000 0.243
#> ATT 0.213 0.026 8.16 0.000 0.242
#> SN 0.176 0.028 6.37 0.000 0.199
#> BEH ~
#> PBC 0.232 0.022 10.37 0.000 0.289
#> INT 0.189 0.025 7.69 0.000 0.212
#> PBC:INT 0.207 0.018 11.32 0.000 0.227
#>
#> Intercepts:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> .pbc1 0.998 0.024 42.41 0.000
#> .pbc2 0.985 0.022 44.93 0.000
#> .pbc3 0.991 0.020 50.45 0.000
#> .att1 1.014 0.024 42.01 0.000
#> .att2 1.007 0.021 46.97 0.000
#> .att3 1.016 0.020 51.45 0.000
#> .att4 0.999 0.018 55.65 0.000
#> .att5 0.992 0.022 45.67 0.000
#> .sn1 1.006 0.024 41.66 0.000
#> .sn2 1.010 0.022 46.70 0.000
#> .int1 1.014 0.022 46.96 0.000
#> .int2 1.012 0.020 50.40 0.000
#> .int3 1.005 0.018 54.80 0.000
#> .b1 1.003 0.021 47.17 0.000
#> .b2 1.021 0.020 51.26 0.000
#>
#> Covariances:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> PBC ~~
#> ATT 0.678 0.029 23.45 0.000 0.692
#> SN 0.678 0.029 23.08 0.000 0.695
#> ATT ~~
#> SN 0.629 0.029 21.70 0.000 0.634
#>
#> Variances:
#> Estimate Std.Error z.value P(>|z|) Std.all
#> .pbc1 0.144 0.008 18.39 0.000 0.130
#> .pbc2 0.160 0.007 21.43 0.000 0.166
#> .pbc3 0.155 0.006 23.89 0.000 0.201
#> .att1 0.167 0.007 23.53 0.000 0.144
#> .att2 0.150 0.006 24.71 0.000 0.164
#> .att3 0.160 0.006 26.38 0.000 0.204
#> .att4 0.162 0.006 27.65 0.000 0.252
#> .att5 0.159 0.006 24.93 0.000 0.168
#> .sn1 0.178 0.015 12.09 0.000 0.153
#> .sn2 0.157 0.012 13.26 0.000 0.167
#> .int1 0.157 0.009 18.11 0.000 0.168
#> .int2 0.160 0.008 20.41 0.000 0.199
#> .int3 0.168 0.007 23.55 0.000 0.249
#> .b1 0.186 0.018 10.12 0.000 0.231
#> .b2 0.135 0.017 8.10 0.000 0.191
#> PBC 0.963 0.036 27.07 0.000 1.000
#> ATT 0.998 0.037 26.93 0.000 1.000
#> SN 0.988 0.039 25.22 0.000 1.000
#> .INT 0.491 0.020 24.64 0.000 0.634
#> .BEH 0.457 0.023 20.17 0.000 0.737