Skip to contents

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                               43
#>   Loglikelihood                               -14687.68
#>   Akaike (AIC)                                 29437.36
#>   Bayesian (BIC)                               29610.98
#>  
#> Numerical Integration:
#>   Points of integration (per dim)                    24
#>   Dimensions                                          1
#>   Total points of integration                        24
#>  
#> Fit Measures for Baseline Model (H0):
#>   Loglikelihood                                  -17832
#>   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.20
#>   Difference test (D)                           6288.39
#>   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|)
#>   X =~ 
#>     x1               0.927      0.004   211.30    0.000
#>     x2               0.891      0.005   166.75    0.000
#>     x3               0.912      0.005   190.11    0.000
#>   Z =~ 
#>     z1               0.927      0.005   201.88    0.000
#>     z2               0.898      0.005   165.02    0.000
#>     z3               0.913      0.005   182.60    0.000
#>   Y =~ 
#>     y1               0.961      0.003   367.69    0.000
#>     y2               0.942      0.003   288.51    0.000
#>     y3               0.951      0.003   326.14    0.000
#> 
#> Regressions:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   Y ~ 
#>     X                0.480      0.018    26.00    0.000
#>     Z                0.416      0.019    21.45    0.000
#>     X:Z              0.514      0.023    22.62    0.000
#> 
#> Covariances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   X ~~ 
#>     Z                0.200      0.023     8.78    0.000
#> 
#> Variances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     x1               0.142      0.008    17.63    0.000
#>     x2               0.206      0.010    21.58    0.000
#>     x3               0.169      0.009    19.54    0.000
#>     z1               0.141      0.008    16.75    0.000
#>     z2               0.193      0.010    19.86    0.000
#>     z3               0.167      0.009    18.38    0.000
#>     y1               0.077      0.005    15.28    0.000
#>     y2               0.113      0.006    18.47    0.000
#>     y3               0.096      0.006    17.31    0.000
#>     X                1.000                             
#>     Z                1.000                             
#>     Y                0.517      0.020    25.80    0.000

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                              110
#>   Loglikelihood                               -17496.22
#>   Akaike (AIC)                                 35054.43
#>   Bayesian (BIC)                               35228.06
#>  
#> Fit Measures for Baseline Model (H0):
#>   Loglikelihood                                  -17832
#>   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                           335.66
#>   Difference test (D)                            671.32
#>   Degrees of freedom (D)                              1
#>   P-value (D)                                     0.000
#>  
#> R-Squared Interaction Model (H1):
#>   Y                                               0.607
#> R-Squared Baseline Model (H0):
#>   Y                                               0.395
#> R-Squared Change (H1 - H0):
#>   Y                                               0.211
#> 
#> 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.914      0.013    67.80    0.000
#>   Z =~ 
#>     z1               1.000                             
#>     z2               0.810      0.012    65.12    0.000
#>     z3               0.881      0.013    67.62    0.000
#>   Y =~ 
#>     y1               1.000                             
#>     y2               0.798      0.007   107.57    0.000
#>     y3               0.899      0.008   112.55    0.000
#> 
#> Regressions:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   Y ~ 
#>     X                0.674      0.032    20.94    0.000
#>     Z                0.566      0.030    18.96    0.000
#>     X:Z              0.712      0.028    25.46    0.000
#> 
#> Intercepts:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     x1               1.023      0.024    42.89    0.000
#>     x2               1.215      0.020    60.99    0.000
#>     x3               0.919      0.022    41.48    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.038      0.033    31.45    0.000
#>     y2               1.221      0.027    45.49    0.000
#>     y3               0.955      0.030    31.86    0.000
#>     Y                0.000                             
#>     X                0.000                             
#>     Z                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.14    0.000
#>     x2               0.162      0.007    23.19    0.000
#>     x3               0.165      0.008    20.82    0.000
#>     z1               0.166      0.009    18.34    0.000
#>     z2               0.159      0.007    22.62    0.000
#>     z3               0.158      0.008    20.71    0.000
#>     y1               0.159      0.009    17.98    0.000
#>     y2               0.154      0.007    22.67    0.000
#>     y3               0.164      0.008    20.71    0.000
#>     X                0.983      0.036    26.99    0.000
#>     Z                1.019      0.038    26.95    0.000
#>     Y                0.943      0.038    24.87    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
#>   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
#>     INT              0.000                             
#>     BEH              0.000                             
#>     PBC              0.000                             
#>     ATT              0.000                             
#>     SN               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
#>   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|)
#>   PBC =~ 
#>     pbc1             0.933      0.004   217.38    0.000
#>     pbc2             0.913      0.005   189.94    0.000
#>     pbc3             0.894      0.005   163.46    0.000
#>   ATT =~ 
#>     att1             0.925      0.004   240.19    0.000
#>     att2             0.915      0.004   211.80    0.000
#>     att3             0.892      0.005   173.63    0.000
#>     att4             0.865      0.006   138.97    0.000
#>     att5             0.912      0.004   207.47    0.000
#>   SN =~ 
#>     sn1              0.921      0.007   128.23    0.000
#>     sn2              0.913      0.007   125.71    0.000
#>   INT =~ 
#>     int1             0.912      0.006   163.04    0.000
#>     int2             0.895      0.006   146.66    0.000
#>     int3             0.866      0.007   125.52    0.000
#>   BEH =~ 
#>     b1               0.870      0.014    62.27    0.000
#>     b2               0.894      0.014    64.03    0.000
#> 
#> Regressions:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   INT ~ 
#>     PBC              0.243      0.032     7.47    0.000
#>     ATT              0.242      0.029     8.27    0.000
#>     SN               0.199      0.031     6.43    0.000
#>   BEH ~ 
#>     PBC              0.299      0.027    10.99    0.000
#>     INT              0.219      0.028     7.89    0.000
#>     PBC:INT          0.235      0.021    11.01    0.000
#> 
#> Covariances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   PBC ~~ 
#>     ATT              0.692      0.013    53.44    0.000
#>     SN               0.695      0.014    51.47    0.000
#>   ATT ~~ 
#>     SN               0.634      0.015    42.01    0.000
#> 
#> Variances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     pbc1             0.130      0.008    16.25    0.000
#>     pbc2             0.166      0.009    18.71    0.000
#>     pbc3             0.201      0.010    20.49    0.000
#>     att1             0.144      0.007    20.09    0.000
#>     att2             0.164      0.008    20.87    0.000
#>     att3             0.204      0.009    22.08    0.000
#>     att4             0.252      0.011    23.48    0.000
#>     att5             0.168      0.008    20.96    0.000
#>     sn1              0.153      0.013    11.49    0.000
#>     sn2              0.167      0.013    12.53    0.000
#>     int1             0.168      0.010    16.45    0.000
#>     int2             0.199      0.011    18.27    0.000
#>     int3             0.249      0.012    20.82    0.000
#>     b1               0.244      0.024    10.05    0.000
#>     b2               0.202      0.025     8.03    0.000
#>     PBC              1.000                             
#>     ATT              1.000                             
#>     SN               1.000                             
#>     INT              0.634      0.019    33.92    0.000
#>     BEH              0.790      0.019    41.41    0.000