Skip to contents
library(modsem)
#> This is modsem (1.0.12). Please report any bugs!

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)
#> 
#> modsem (1.0.12) ended normally after 43 iterations
#> 
#>   Estimator                                        LMS
#>   Optimization method                       EMA-NLMINB
#>   Number of model parameters                        31
#>                                                       
#>   Number of observations                          2000
#>  
#> Loglikelihood and Information Criteria:
#>   Loglikelihood                              -17493.60
#>   Akaike (AIC)                                35049.20
#>   Bayesian (BIC)                              35222.83
#>  
#> 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                          338.27
#>   Difference test (D)                           676.55
#>   Degrees of freedom (D)                             1
#>   P-value (D)                                    0.000
#>  
#> R-Squared Interaction Model (H1):
#>   Y                                              0.599
#> R-Squared Baseline Model (H0):
#>   Y                                              0.395
#> R-Squared Change (H1 - H0):
#>   Y                                              0.204
#> 
#> 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.928
#>     x2              0.804      0.013   63.806    0.000    0.892
#>     x3              0.914      0.014   67.599    0.000    0.913
#>   Z =~          
#>     z1              1.000                                 0.927
#>     z2              0.810      0.012   65.079    0.000    0.898
#>     z3              0.881      0.013   67.610    0.000    0.913
#>   Y =~          
#>     y1              1.000                                 0.969
#>     y2              0.798      0.007  107.547    0.000    0.954
#>     y3              0.899      0.008  112.574    0.000    0.961
#> 
#> Regressions:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>   Y ~           
#>     X               0.674      0.031   21.689    0.000    0.427
#>     Z               0.570      0.030   18.739    0.000    0.368
#>     X:Z             0.718      0.028   25.829    0.000    0.459
#> 
#> Intercepts:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>    .x1              1.023      0.024   42.812    0.000         
#>    .x2              1.216      0.020   60.879    0.000         
#>    .x3              0.920      0.022   41.405    0.000         
#>    .z1              1.012      0.024   41.586    0.000         
#>    .z2              1.206      0.020   59.281    0.000         
#>    .z3              0.916      0.022   42.072    0.000         
#>    .y1              1.037      0.033   31.391    0.000         
#>    .y2              1.220      0.027   45.413    0.000         
#>    .y3              0.954      0.030   31.800    0.000         
#> 
#> Covariances:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>   X ~~          
#>     Z               0.200      0.024    8.241    0.000    0.200
#> 
#> Variances:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>    .x1              0.158      0.009   18.169    0.000    0.139
#>    .x2              0.162      0.007   23.156    0.000    0.204
#>    .x3              0.165      0.008   20.755    0.000    0.167
#>    .z1              0.167      0.009   18.505    0.000    0.141
#>    .z2              0.160      0.007   22.680    0.000    0.193
#>    .z3              0.158      0.008   20.777    0.000    0.167
#>    .y1              0.160      0.009   18.010    0.000    0.061
#>    .y2              0.154      0.007   22.684    0.000    0.090
#>    .y3              0.164      0.008   20.681    0.000    0.076
#>     X               0.981      0.036   26.966    0.000    1.000
#>     Z               1.017      0.038   26.930    0.000    1.000
#>    .Y               0.980      0.038   25.934    0.000    0.401

Here is the same example using the QML approach:

qml1 <- modsem(m1, oneInt, method = "qml")
summary(qml1)
#> 
#> modsem (1.0.12) ended normally after 94 iterations
#> 
#>   Estimator                                        QML
#>   Optimization method                           NLMINB
#>   Number of model parameters                        31
#>                                                       
#>   Number of observations                          2000
#>  
#> Loglikelihood and Information Criteria:
#>   Loglikelihood                              -17493.65
#>   Akaike (AIC)                                35049.30
#>   Bayesian (BIC)                              35222.92
#>  
#> 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                          338.23
#>   Difference test (D)                           676.45
#>   Degrees of freedom (D)                             1
#>   P-value (D)                                    0.000
#>  
#> R-Squared Interaction Model (H1):
#>   Y                                              0.599
#> R-Squared Baseline Model (H0):
#>   Y                                              0.395
#> R-Squared Change (H1 - H0):
#>   Y                                              0.204
#> 
#> Parameter Estimates:
#>   Coefficients                          unstandardized
#>   Information                                 observed
#>   Standard errors                             standard
#>  
#> Latent Variables:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>   X =~          
#>     x1              1.000                             
#>     x2              0.804      0.013   63.897    0.000
#>     x3              0.914      0.013   67.710    0.000
#>   Z =~          
#>     z1              1.000                             
#>     z2              0.810      0.012   65.076    0.000
#>     z3              0.881      0.013   67.604    0.000
#>   Y =~          
#>     y1              1.000                             
#>     y2              0.798      0.007  107.528    0.000
#>     y3              0.899      0.008  112.559    0.000
#> 
#> Regressions:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>   Y ~           
#>     X               0.674      0.031   21.688    0.000
#>     Z               0.569      0.030   18.738    0.000
#>     X:Z             0.718      0.028   25.829    0.000
#> 
#> Intercepts:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>    .x1              1.023      0.024   42.849    0.000
#>    .x2              1.216      0.020   60.927    0.000
#>    .x3              0.920      0.022   41.443    0.000
#>    .z1              1.012      0.024   41.582    0.000
#>    .z2              1.206      0.020   59.274    0.000
#>    .z3              0.916      0.022   42.068    0.000
#>    .y1              1.038      0.033   31.420    0.000
#>    .y2              1.221      0.027   45.440    0.000
#>    .y3              0.954      0.030   31.823    0.000
#> 
#> Covariances:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>   X ~~          
#>     Z               0.200      0.024    8.239    0.000
#> 
#> Variances:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>    .x1              0.158      0.009   18.145    0.000
#>    .x2              0.162      0.007   23.154    0.000
#>    .x3              0.165      0.008   20.767    0.000
#>    .z1              0.167      0.009   18.506    0.000
#>    .z2              0.160      0.007   22.675    0.000
#>    .z3              0.158      0.008   20.770    0.000
#>    .y1              0.160      0.009   18.011    0.000
#>    .y2              0.154      0.007   22.681    0.000
#>    .y3              0.164      0.008   20.678    0.000
#>     X               0.983      0.036   26.974    0.000
#>     Z               1.017      0.038   26.927    0.000
#>    .Y               0.980      0.038   25.908    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 24, 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)
#> 
#> modsem (1.0.12) ended normally after 34 iterations
#> 
#>   Estimator                                        LMS
#>   Optimization method                       EMA-NLMINB
#>   Number of model parameters                        54
#>                                                       
#>   Number of observations                          2000
#>  
#> Loglikelihood and Information Criteria:
#>   Loglikelihood                              -26326.02
#>   Akaike (AIC)                                52760.04
#>   Bayesian (BIC)                              53062.49
#>  
#> 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                           67.20
#>   Difference test (D)                           134.40
#>   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.001
#>   BEH                                            0.053
#> 
#> Parameter Estimates:
#>   Coefficients                          unstandardized
#>   Information                                 observed
#>   Standard errors                             standard
#>  
#> Latent Variables:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>   ATT =~        
#>     att1            1.000                             
#>     att2            0.878      0.012   71.566    0.000
#>     att3            0.789      0.012   66.377    0.000
#>     att4            0.695      0.011   61.002    0.000
#>     att5            0.887      0.013   70.853    0.000
#>   SN =~         
#>     sn1             1.000                             
#>     sn2             0.888      0.017   52.599    0.000
#>   PBC =~        
#>     pbc1            1.000                             
#>     pbc2            0.912      0.013   69.356    0.000
#>     pbc3            0.801      0.012   66.005    0.000
#>   INT =~        
#>     int1            1.000                             
#>     int2            0.913      0.015   59.059    0.000
#>     int3            0.807      0.014   55.740    0.000
#>   BEH =~        
#>     b1              1.000                             
#>     b2              0.961      0.030   31.749    0.000
#> 
#> Regressions:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>   INT ~         
#>     ATT             0.213      0.026    8.166    0.000
#>     SN              0.176      0.028    6.388    0.000
#>     PBC             0.217      0.030    7.346    0.000
#>   BEH ~         
#>     PBC             0.233      0.022   10.410    0.000
#>     INT             0.189      0.025    7.682    0.000
#>     INT:PBC         0.205      0.018   11.309    0.000
#> 
#> Intercepts:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>    .pbc1            0.998      0.024   42.438    0.000
#>    .pbc2            0.985      0.022   44.959    0.000
#>    .pbc3            0.991      0.020   50.481    0.000
#>    .att1            1.014      0.024   42.020    0.000
#>    .att2            1.007      0.021   46.987    0.000
#>    .att3            1.017      0.020   51.476    0.000
#>    .att4            0.999      0.018   55.675    0.000
#>    .att5            0.992      0.022   45.691    0.000
#>    .sn1             1.006      0.024   41.679    0.000
#>    .sn2             1.011      0.022   46.730    0.000
#>    .int1            1.014      0.022   46.976    0.000
#>    .int2            1.013      0.020   50.421    0.000
#>    .int3            1.005      0.018   54.821    0.000
#>    .b1              1.001      0.021   46.997    0.000
#>    .b2              1.019      0.020   51.075    0.000
#> 
#> Covariances:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>   ATT ~~        
#>     SN              0.629      0.029   21.946    0.000
#>   PBC ~~        
#>     ATT             0.678      0.029   23.717    0.000
#>     SN              0.677      0.029   23.337    0.000
#> 
#> Variances:
#>                  Estimate  Std.Error  z.value  P(>|z|)
#>    .pbc1            0.144      0.008   18.396    0.000
#>    .pbc2            0.160      0.007   21.439    0.000
#>    .pbc3            0.155      0.006   23.896    0.000
#>    .att1            0.167      0.007   23.535    0.000
#>    .att2            0.150      0.006   24.720    0.000
#>    .att3            0.159      0.006   26.387    0.000
#>    .att4            0.162      0.006   27.654    0.000
#>    .att5            0.159      0.006   24.932    0.000
#>    .sn1             0.178      0.015   12.086    0.000
#>    .sn2             0.157      0.012   13.256    0.000
#>    .int1            0.157      0.009   18.107    0.000
#>    .int2            0.160      0.008   20.412    0.000
#>    .int3            0.168      0.007   23.554    0.000
#>    .b1              0.186      0.018   10.131    0.000
#>    .b2              0.135      0.017    8.124    0.000
#>     ATT             0.998      0.037   27.140    0.000
#>     SN              0.987      0.039   25.408    0.000
#>     PBC             0.962      0.035   27.248    0.000
#>    .INT             0.491      0.020   24.647    0.000
#>    .BEH             0.455      0.023   20.143    0.000

qml2 <- modsem(tpb, TPB, method = "qml")
summary(qml2, standardized = TRUE) # Standardized estimates
#> 
#> modsem (1.0.12) ended normally after 70 iterations
#> 
#>   Estimator                                        QML
#>   Optimization method                           NLMINB
#>   Number of model parameters                        54
#>                                                       
#>   Number of observations                          2000
#>  
#> Loglikelihood and Information Criteria:
#>   Loglikelihood                              -26326.05
#>   Akaike (AIC)                                52760.10
#>   Bayesian (BIC)                              53062.55
#>  
#> 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                           67.17
#>   Difference test (D)                           134.34
#>   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
#>   ATT =~        
#>     att1            1.000                                 0.925
#>     att2            0.878      0.012   71.563    0.000    0.915
#>     att3            0.789      0.012   66.375    0.000    0.892
#>     att4            0.695      0.011   61.000    0.000    0.865
#>     att5            0.887      0.013   70.851    0.000    0.912
#>   SN =~         
#>     sn1             1.000                                 0.921
#>     sn2             0.888      0.017   52.615    0.000    0.913
#>   PBC =~        
#>     pbc1            1.000                                 0.933
#>     pbc2            0.912      0.013   69.469    0.000    0.913
#>     pbc3            0.801      0.012   66.098    0.000    0.894
#>   INT =~        
#>     int1            1.000                                 0.912
#>     int2            0.913      0.015   59.045    0.000    0.895
#>     int3            0.807      0.014   55.730    0.000    0.867
#>   BEH =~        
#>     b1              1.000                                 0.877
#>     b2              0.960      0.030   31.747    0.000    0.899
#> 
#> Regressions:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>   INT ~         
#>     ATT             0.213      0.026    8.164    0.000    0.242
#>     SN              0.176      0.028    6.386    0.000    0.199
#>     PBC             0.217      0.030    7.349    0.000    0.242
#>   BEH ~         
#>     PBC             0.232      0.022   10.407    0.000    0.290
#>     INT             0.189      0.025    7.680    0.000    0.212
#>     INT:PBC         0.205      0.018   11.309    0.000    0.225
#> 
#> Intercepts:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>    .int1            1.014      0.022   46.961    0.000         
#>    .int2            1.012      0.020   50.402    0.000         
#>    .int3            1.005      0.018   54.801    0.000         
#>    .att1            1.014      0.024   42.004    0.000         
#>    .att2            1.007      0.021   46.964    0.000         
#>    .att3            1.016      0.020   51.452    0.000         
#>    .att4            0.999      0.018   55.651    0.000         
#>    .att5            0.992      0.022   45.669    0.000         
#>    .sn1             1.006      0.024   41.656    0.000         
#>    .sn2             1.010      0.022   46.705    0.000         
#>    .pbc1            0.998      0.024   42.411    0.000         
#>    .pbc2            0.985      0.022   44.931    0.000         
#>    .pbc3            0.991      0.020   50.451    0.000         
#>    .b1              1.001      0.021   46.995    0.000         
#>    .b2              1.019      0.020   51.073    0.000         
#> 
#> Covariances:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>   ATT ~~        
#>     SN              0.629      0.029   21.696    0.000    0.634
#>     PBC             0.678      0.029   23.450    0.000    0.692
#>   SN ~~         
#>     PBC             0.678      0.029   23.076    0.000    0.695
#> 
#> Variances:
#>                  Estimate  Std.Error  z.value  P(>|z|)  Std.all
#>    .int1            0.157      0.009   18.106    0.000    0.168
#>    .int2            0.160      0.008   20.407    0.000    0.199
#>    .int3            0.168      0.007   23.547    0.000    0.249
#>    .att1            0.167      0.007   23.532    0.000    0.144
#>    .att2            0.150      0.006   24.714    0.000    0.164
#>    .att3            0.160      0.006   26.380    0.000    0.204
#>    .att4            0.162      0.006   27.647    0.000    0.252
#>    .att5            0.159      0.006   24.926    0.000    0.168
#>    .sn1             0.178      0.015   12.089    0.000    0.153
#>    .sn2             0.157      0.012   13.255    0.000    0.167
#>    .pbc1            0.144      0.008   18.390    0.000    0.130
#>    .pbc2            0.160      0.007   21.431    0.000    0.166
#>    .pbc3            0.155      0.006   23.886    0.000    0.201
#>    .b1              0.186      0.018   10.123    0.000    0.231
#>    .b2              0.135      0.017    8.130    0.000    0.192
#>     ATT             0.998      0.037   26.933    0.000    1.000
#>     SN              0.988      0.039   25.224    0.000    1.000
#>     PBC             0.963      0.036   27.065    0.000    1.000
#>    .INT             0.491      0.020   24.641    0.000    0.634
#>    .BEH             0.455      0.023   20.139    0.000    0.737