The LMS and QML approaches are implemented in modsem. Currently the QML approach is only implented for simpler models with a single endogenous (i.e., dependent) variable. The LMS approach however works on most models, except for models where there is an interaction between two endogenous (i.e., dependent) variables. Both approaches (particularily the LMS approach) are quite computationally intensive, and are thus partly 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 see the progress of the estimation process you can use ´verbose = TRUE´.
A Simple Example
Here you can see 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
X =~ x2 + x3
Z =~ z1 + z2 + z3
Y =~ y1 + y2 + y3
# Inner model
Y ~ X + Z
Y ~ X:Z
'
lms1 <- modsem (m1, oneInt, method = "lms" )
summary (lms1)
Estimating null model
EM: Iteration = 1, LogLik = -17831.87, Change = -17831.875
EM: Iteration = 2, LogLik = -17831.87, Change = 0.000
Calculating Hessian
----Model Summary------------------------------------------------------
Number of iterations: 32
Final loglikelihood: -14806.42
Comparative fit to H0 (no interaction effect)
D(1) = -6051, p = < 2.22e-16
R-squared:
Y = 0.596
R-squared Null-Model (H0):
Y = 0.395
R-squared Change:
Y = 0.201
----Estimates----------------------------------------------------------
Loadings:
X:
variable est std.error t.value p.value ci.lower ci.upper
x1 1.000 NA NA NA NA NA
x2 0.807 0.0120 67.5 < 2.22e-16 0.783 0.830
x3 0.917 0.0128 71.9 < 2.22e-16 0.892 0.942
Z:
variable est std.error t.value p.value ci.lower ci.upper
z1 1.000 NA NA NA NA NA
z2 0.810 0.0124 65.1 < 2.22e-16 0.786 0.835
z3 0.881 0.0130 67.7 < 2.22e-16 0.855 0.906
Regressions:
Y:
variable est std.error t.value p.value ci.lower ci.upper
X 0.689 0.0302 22.8 < 2.22e-16 0.630 0.748
Z 0.605 0.0252 24.0 < 2.22e-16 0.556 0.655
X:Z 0.723 0.0268 27.0 < 2.22e-16 0.670 0.775
Intercepts:
variable est std.error t.value p.value ci.lower ci.upper
x1 1.065 0.00926 115.1 < 2.22e-16 1.047 1.083
x2 1.249 0.00910 137.3 < 2.22e-16 1.232 1.267
x3 0.958 0.00924 103.6 < 2.22e-16 0.940 0.976
z1 1.028 0.02396 42.9 < 2.22e-16 0.981 1.075
z2 1.219 0.02005 60.8 < 2.22e-16 1.180 1.259
z3 0.931 0.02144 43.4 < 2.22e-16 0.889 0.973
y1 1.086 0.02817 38.5 < 2.22e-16 1.030 1.141
y2 1.259 0.02308 54.6 < 2.22e-16 1.214 1.304
y3 0.998 0.02567 38.9 < 2.22e-16 0.947 1.048
Variances:
variable est std.error t.value p.value ci.lower ci.upper
x1 0.171 0.00541 31.62 < 2.22e-16 0.160 0.182
x2 0.165 0.00523 31.62 < 2.22e-16 0.155 0.176
x3 0.171 0.00539 31.62 < 2.22e-16 0.160 0.181
z1 0.167 0.00898 18.55 < 2.22e-16 0.149 0.184
z2 0.160 0.00703 22.72 < 2.22e-16 0.146 0.173
z3 0.158 0.00760 20.83 < 2.22e-16 0.143 0.173
y1 0.160 0.00884 18.04 < 2.22e-16 0.142 0.177
y2 0.154 0.00681 22.69 < 2.22e-16 0.141 0.168
y3 0.164 0.00789 20.73 < 2.22e-16 0.148 0.179
X 0.913 0.00900 101.53 < 2.22e-16 0.896 0.931
Z 0.184 0.02221 8.27 < 2.22e-16 0.140 0.227
Z 1.016 0.01840 55.21 < 2.22e-16 0.980 1.052
Y 0.991 0.03640 27.22 < 2.22e-16 0.920 1.062
Here you can see the same example using the QML approach.
qml1 <- modsem (m1, oneInt, method = "qml" )
summary (qml1)
Estimating null model
Starting M-step
Calculating Hessian
----Model Summary------------------------------------------------------
Number of iterations: 25
Final loglikelihood: -17496.81
Comparative fit to H0 (no interaction effect)
D(1) = -670, p = < 2.22e-16
R-squared:
Y = 0.609
R-squared Null-Model (H0):
Y = 0.395
R-squared Change:
Y = 0.213
----Estimates----------------------------------------------------------
Loadings:
X:
variable est std.error t.value p.value ci.lower ci.upper
x1 1.000 NA NA NA NA NA
x2 0.803 0.0125 64.0 < 2.22e-16 0.778 0.827
x3 0.914 0.0135 67.8 < 2.22e-16 0.887 0.940
Z:
variable est std.error t.value p.value ci.lower ci.upper
z1 1.000 NA NA NA NA NA
z2 0.810 0.0124 65.2 < 2.22e-16 0.786 0.834
z3 0.881 0.0130 67.7 < 2.22e-16 0.855 0.906
Regressions:
Y:
variable est std.error t.value p.value ci.lower ci.upper
X 0.686 0.0322 21.3 < 2.22e-16 0.622 0.749
Z 0.577 0.0299 19.3 < 2.22e-16 0.518 0.636
X:Z 0.706 0.0279 25.3 < 2.22e-16 0.651 0.761
Intercepts:
variable est std.error t.value p.value ci.lower ci.upper
x1 1.038 0.0239 43.5 < 2.22e-16 0.991 1.085
x2 1.228 0.0199 61.6 < 2.22e-16 1.189 1.267
x3 0.934 0.0222 42.0 < 2.22e-16 0.890 0.977
z1 1.026 0.0244 42.1 < 2.22e-16 0.978 1.074
z2 1.217 0.0204 59.7 < 2.22e-16 1.177 1.257
z3 0.928 0.0218 42.6 < 2.22e-16 0.886 0.971
y1 1.070 0.0334 32.1 < 2.22e-16 1.005 1.135
y2 1.247 0.0271 45.9 < 2.22e-16 1.193 1.300
y3 0.984 0.0303 32.5 < 2.22e-16 0.924 1.043
Variances:
variable est std.error t.value p.value ci.lower ci.upper
x1 0.158 0.00871 18.13 < 2.22e-16 0.141 0.175
x2 0.162 0.00697 23.19 < 2.22e-16 0.148 0.175
x3 0.165 0.00794 20.80 < 2.22e-16 0.149 0.181
z1 0.165 0.00902 18.34 < 2.22e-16 0.148 0.183
z2 0.159 0.00703 22.63 < 2.22e-16 0.145 0.173
z3 0.158 0.00762 20.72 < 2.22e-16 0.143 0.173
y1 0.159 0.00888 17.94 < 2.22e-16 0.142 0.177
y2 0.155 0.00685 22.63 < 2.22e-16 0.142 0.168
y3 0.164 0.00791 20.69 < 2.22e-16 0.148 0.179
X 0.984 0.03643 27.00 < 2.22e-16 0.912 1.055
Z 0.199 0.02431 8.18 2.7693e-16 0.151 0.247
Z 1.019 0.03780 26.96 < 2.22e-16 0.945 1.093
Y 0.951 0.03840 24.76 < 2.22e-16 0.875 1.026
A more complicated example
Here you can see an example of a more complicated example using the model from the theory of planned behaviour (TPB), where there are two endogenous variables, where there is an interaction between an endogenous and exogenous variable. (note this does not work with the QML approach). For more complicated models, it is recommended that you increase the number of nodes used for numerical integration. By default the number of nodes is set to 16, and can be increased using the nodes argument.
# ATT = Attitude,
# PBC = Perceived Behavioural Control
# INT = Intention
# SN = Subjective Norms
# BEH = 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)
# Covariances
ATT ~~ SN + PBC
PBC ~~ SN
# Causal Relationsships
INT ~ ATT + SN + PBC
BEH ~ INT + PBC
BEH ~ INT:PBC
'
lms2 <- modsem (tpb, TPB, method = "lms" , nodes = 20 )
summary (lms2)
Estimating null model
EM: Iteration = 1, LogLik = -26393.22, Change = -26393.223
EM: Iteration = 2, LogLik = -26393.22, Change = 0.000
Calculating Hessian
----Model Summary------------------------------------------------------
Number of iterations: 29
Final loglikelihood: -23520.44
Comparative fit to H0 (no interaction effect)
D(1) = -5746, p = < 2.22e-16
R-squared:
INT = 0.357
BEH = 0.252
R-squared Null-Model (H0):
INT = 0.367
BEH = 0.210
R-squared Change:
INT = -0.00987
BEH = 0.04218
----Estimates----------------------------------------------------------
Loadings:
PBC:
variable est std.error t.value p.value ci.lower ci.upper
pbc1 1.000 NA NA NA NA NA
pbc2 0.912 0.0123 73.9 < 2.22e-16 0.888 0.936
pbc3 0.802 0.0115 69.5 < 2.22e-16 0.779 0.824
ATT:
variable est std.error t.value p.value ci.lower ci.upper
att1 1.000 NA NA NA NA NA
att2 0.878 0.0123 71.6 < 2.22e-16 0.854 0.902
att3 0.789 0.0119 66.4 < 2.22e-16 0.765 0.812
att4 0.695 0.0114 61.0 < 2.22e-16 0.672 0.717
att5 0.887 0.0125 70.9 < 2.22e-16 0.862 0.911
SN:
variable est std.error t.value p.value ci.lower ci.upper
sn1 1.000 NA NA NA NA NA
sn2 0.888 0.0167 53.1 < 2.22e-16 0.855 0.921
Regressions:
INT:
variable est std.error t.value p.value ci.lower ci.upper
PBC 0.214 0.0276 7.77 7.6879e-15 0.160 0.268
ATT 0.215 0.0257 8.39 < 2.22e-16 0.165 0.266
SN 0.178 0.0272 6.55 5.7083e-11 0.125 0.231
BEH:
variable est std.error t.value p.value ci.lower ci.upper
PBC 0.231 0.0214 10.83 < 2.22e-16 0.190 0.273
INT 0.189 0.0238 7.95 1.9337e-15 0.142 0.236
PBC:INT 0.206 0.0178 11.59 < 2.22e-16 0.171 0.241
Intercepts:
variable est std.error t.value p.value ci.lower ci.upper
pbc1 0.988 0.00867 114.0 < 2.22e-16 0.971 1.005
pbc2 0.976 0.00910 107.3 < 2.22e-16 0.958 0.994
pbc3 0.983 0.00886 111.0 < 2.22e-16 0.966 1.001
att1 1.011 0.01858 54.4 < 2.22e-16 0.974 1.047
att2 1.004 0.01663 60.4 < 2.22e-16 0.972 1.037
att3 1.014 0.01557 65.1 < 2.22e-16 0.983 1.044
att4 0.997 0.01440 69.2 < 2.22e-16 0.968 1.025
att5 0.989 0.01689 58.6 < 2.22e-16 0.956 1.023
sn1 1.001 0.01858 53.9 < 2.22e-16 0.965 1.038
sn2 1.007 0.01675 60.1 < 2.22e-16 0.974 1.039
int1 1.012 0.01872 54.1 < 2.22e-16 0.975 1.049
int2 1.011 0.01752 57.7 < 2.22e-16 0.976 1.045
int3 1.004 0.01616 62.1 < 2.22e-16 0.972 1.035
b1 0.999 0.01997 50.0 < 2.22e-16 0.960 1.038
b2 1.017 0.01865 54.6 < 2.22e-16 0.981 1.054
Variances:
variable est std.error t.value p.value ci.lower ci.upper
pbc1 0.150 0.00475 31.62 < 2.22e-16 0.141 0.160
pbc2 0.165 0.00523 31.62 < 2.22e-16 0.155 0.176
pbc3 0.157 0.00496 31.62 < 2.22e-16 0.147 0.167
att1 0.167 0.00709 23.56 < 2.22e-16 0.153 0.181
att2 0.150 0.00606 24.76 < 2.22e-16 0.138 0.162
att3 0.159 0.00603 26.42 < 2.22e-16 0.148 0.171
att4 0.162 0.00586 27.69 < 2.22e-16 0.151 0.174
att5 0.159 0.00636 24.97 < 2.22e-16 0.146 0.171
sn1 0.178 0.01447 12.28 < 2.22e-16 0.149 0.206
sn2 0.157 0.01162 13.49 < 2.22e-16 0.134 0.179
int1 0.157 0.00865 18.12 < 2.22e-16 0.140 0.174
int2 0.160 0.00785 20.41 < 2.22e-16 0.145 0.176
int3 0.168 0.00712 23.56 < 2.22e-16 0.154 0.182
b1 0.186 0.01811 10.27 < 2.22e-16 0.150 0.221
b2 0.135 0.01636 8.25 < 2.22e-16 0.103 0.167
PBC 0.913 0.00849 107.53 < 2.22e-16 0.896 0.929
ATT 0.643 0.01734 37.08 < 2.22e-16 0.609 0.677
SN 0.643 0.01804 35.65 < 2.22e-16 0.608 0.679
ATT 0.977 0.01374 71.07 < 2.22e-16 0.950 1.004
SN 0.608 0.01789 33.97 < 2.22e-16 0.573 0.643
SN 0.966 0.01468 65.85 < 2.22e-16 0.938 0.995
INT 0.492 0.01988 24.74 < 2.22e-16 0.453 0.531
BEH 0.455 0.02241 20.32 < 2.22e-16 0.411 0.499