Skip to contents

The Latent Moderated Structural Equations (LMS) and the Quasi Maximum Likelihood (QML) approach

In contrast to the other approaches, the LMS and QML approaches are designed to handle latent variables only. Thus observed variables cannot be as easily used, as in the other approaches. One way of getting around this is by specifying your observed variable as a latent variable with a single indicator. modsem() will by default constrain the factor loading to 1, and the residual variance of the indicator to 0. Then, the only difference between the latent variable and its indicator, is that (assuming that it is an exogenous variable) it has a zero-mean. This will work for both the LMS- and QML approach in most cases, except for two exceptions.

The LMS approach

For the LMS approach you can use the above mentioned approach in almost all cases, except in the case where you wish to use an observed variable as a moderating variable. In the LMS approach, you will usually select one variable in an interaction term as a moderator. The interaction effect is then estimated via numerical integration, at n quadrature nodes of the moderating variable. This process however, requires that the moderating variable has an error-term, as the distribution of the moderating variable is modelled as XN(Az,ε)X \sim N(Az, \varepsilon), where AzAz is the expected value of XX at quadrature point k, and ε\varepsilon is the error term. If the error-term is zero, the probability of observing a given value of XX will not be computable. In most instances the first variable in the interaction term, is chosen as the moderator. For example, if the interaction term is "X:Z", "X" will usually be chosen as the moderator. Thus if only one of the variables are latent, you should put the latent variable first in the interaction term. If both are observed, you have to specify a measurement error (e.g., “x1 ~~ 0.1 * x1”) for the indicator of the first variable in the interaction term.

library(modsem)

# interaction effect between a latent and an observed variable
m1 <- '
# Outer Model
  X =~ x1 # X is observed
  Z =~ z1 + z2 # Z is latent
  Y =~ y1 # Y is observed

# Inner model
  Y ~ X + Z
  Y ~ Z:X
'

lms1 <- modsem(m1, oneInt, method = "lms")

# interaction effect between two observed variables
m2 <- '
# Outer Model
  X =~ x1 # X is observed
  Z =~ z1 # Z is observed
  Y =~ y1 # Y is observed
  x1 ~~ 0.1 * x1 # specify a variance for the measurement error
# Inner model
  Y ~ X + Z
  Y ~ X:Z
'

lms2 <- modsem(m1, oneInt, method = "lms")
summary(lms2)
#> Estimating null model
#> EM: Iteration =     1, LogLik =   -10816.13, Change = -10816.126
#> EM: Iteration =     2, LogLik =   -10816.13, Change =      0.000
#> 
#> modsem (version 1.0.2):
#>   Estimator                                         LMS
#>   Optimization method                         EM-NLMINB
#>   Number of observations                           2000
#>   Number of iterations                               58
#>   Loglikelihood                                 -8087.2
#>   Akaike (AIC)                                  16202.4
#>   Bayesian (BIC)                               16280.81
#>  
#> Numerical Integration:
#>   Points of integration (per dim)                    24
#>   Dimensions                                          1
#>   Total points of integration                        24
#>  
#> Fit Measures for H0:
#>   Loglikelihood                                  -10816
#>   Akaike (AIC)                                 21658.25
#>   Bayesian (BIC)                               21731.06
#>   Chi-square                                       0.01
#>   Degrees of Freedom (Chi-square)                     1
#>   P-value (Chi-square)                            0.917
#>   RMSEA                                           0.000
#>  
#> Comparative fit to H0 (no interaction effect)
#>   Loglikelihood change                          2728.93
#>   Difference test (D)                           5457.85
#>   Degrees of freedom (D)                              1
#>   P-value (D)                                     0.000
#>  
#> R-Squared:
#>   Y                                               0.510
#> R-Squared Null-Model (H0):
#>   Y                                               0.343
#> R-Squared Change:
#>   Y                                               0.167
#> 
#> Parameter Estimates:
#>   Coefficients                           unstandardized
#>   Information                                  expected
#>   Standard errors                              standard
#>  
#> Latent Variables:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   Z =~ 
#>     z1               1.000                             
#>     z2               0.811      0.018    45.02    0.000
#>   X =~ 
#>     x1               1.000                             
#>   Y =~ 
#>     y1               1.000                             
#> 
#> Regressions:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   Y ~ 
#>     Z                0.587      0.033    18.04    0.000
#>     X                0.574      0.029    20.07    0.000
#>     Z:X              0.627      0.027    23.51    0.000
#> 
#> Intercepts:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     z1               1.009      0.024    42.79    0.000
#>     z2               1.203      0.020    60.79    0.000
#>     x1               1.023      0.024    42.76    0.000
#>     y1               1.046      0.033    31.42    0.000
#>     Y                0.000                             
#>     Z                0.000                             
#>     X                0.000                             
#> 
#> Covariances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   Z ~~ 
#>     X                0.211      0.025     8.54    0.000
#> 
#> Variances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     z1               0.170      0.018     9.21    0.000
#>     z2               0.160      0.013    12.71    0.000
#>     x1               0.000                             
#>     y1               0.000                             
#>     Z                1.010      0.020    51.00    0.000
#>     X                1.141      0.017    67.45    0.000
#>     Y                1.284      0.043    29.98    0.000

The QML approach

If you are using the latest GitHub version

The estimation of the QML approach is different from the LMS approach, and you do not have the same issue as in the LMS approach. Thus you don’t have to specify a measurement error for moderating variables.

m3 <- '
# Outer Model
  X =~ x1 # X is observed
  Z =~ z1 # Z is observed
  Y =~ y1 # Y is observed

# Inner model
  Y ~ X + Z
  Y ~ X:Z
'

qml3 <- modsem(m3, oneInt, method = "qml")
summary(qml3)
#> Estimating null model
#> Starting M-step
#> 
#> modsem (version 1.0.2):
#>   Estimator                                         QML
#>   Optimization method                            NLMINB
#>   Number of observations                           2000
#>   Number of iterations                               11
#>   Loglikelihood                                -9117.07
#>   Akaike (AIC)                                 18254.13
#>   Bayesian (BIC)                               18310.14
#>  
#> Fit Measures for H0:
#>   Loglikelihood                                   -9369
#>   Akaike (AIC)                                 18756.46
#>   Bayesian (BIC)                               18806.87
#>   Chi-square                                       0.00
#>   Degrees of Freedom (Chi-square)                     0
#>   P-value (Chi-square)                            0.000
#>   RMSEA                                           0.000
#>  
#> Comparative fit to H0 (no interaction effect)
#>   Loglikelihood change                           252.17
#>   Difference test (D)                            504.33
#>   Degrees of freedom (D)                              1
#>   P-value (D)                                     0.000
#>  
#> R-Squared:
#>   Y                                               0.470
#> R-Squared Null-Model (H0):
#>   Y                                               0.320
#> R-Squared Change:
#>   Y                                               0.150
#> 
#> Parameter Estimates:
#>   Coefficients                           unstandardized
#>   Information                                  observed
#>   Standard errors                              standard
#>  
#> Latent Variables:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   X =~ 
#>     x1               1.000                             
#>   Z =~ 
#>     z1               1.000                             
#>   Y =~ 
#>     y1               1.000                             
#> 
#> Regressions:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   Y ~ 
#>     X                0.605      0.028    21.26    0.000
#>     Z                0.490      0.028    17.55    0.000
#>     X:Z              0.544      0.023    23.95    0.000
#> 
#> Intercepts:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     x1               1.023      0.024    42.83    0.000
#>     z1               1.011      0.024    41.56    0.000
#>     y1               1.066      0.034    31.64    0.000
#>     Y                0.000                             
#>     X                0.000                             
#>     Z                0.000                             
#> 
#> Covariances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   X ~~ 
#>     Z                0.210      0.026     7.95    0.000
#> 
#> Variances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     x1               0.000                             
#>     z1               0.000                             
#>     y1               0.000                             
#>     X                1.141      0.036    31.62    0.000
#>     Z                1.184      0.037    31.62    0.000
#>     Y                1.399      0.044    31.62    0.000

If you are using the CRAN version

If you are using the latest CRAN version, there is a slight caveat, in that all endogenous variables have to have atleast two indicators. This is due to a transformation, and the approximation of the distribution of the indicators in the endogenous variables. This problem will likely be fixed in a later update, but as of now, latent endogenous variable need at least two indicators. If a latent variable in the QML approach can be expressed without using an interaction term, you can in some cases use the ‘cov.syntax’ argument as a workaround. If this is the case, see the vignette on interaction effects between two endogenous variable in the LMS- and QML approach (vignette("interaction_two_etas"))

m4 <- '
# Outer Model
  X =~ x1 # X is observed
  Z =~ z1 # Z is observed
  Y =~ y1 + y2 # Y needs to be latent, needing atleast two indicators

# Inner model
  Y ~ X + Z
  Y ~ X:Z
'

qml4 <- modsem(m3, oneInt, method = "qml")
summary(qml4)
#> Estimating null model
#> Starting M-step
#> 
#> modsem (version 1.0.2):
#>   Estimator                                         QML
#>   Optimization method                            NLMINB
#>   Number of observations                           2000
#>   Number of iterations                               11
#>   Loglikelihood                                -9117.07
#>   Akaike (AIC)                                 18254.13
#>   Bayesian (BIC)                               18310.14
#>  
#> Fit Measures for H0:
#>   Loglikelihood                                   -9369
#>   Akaike (AIC)                                 18756.46
#>   Bayesian (BIC)                               18806.87
#>   Chi-square                                       0.00
#>   Degrees of Freedom (Chi-square)                     0
#>   P-value (Chi-square)                            0.000
#>   RMSEA                                           0.000
#>  
#> Comparative fit to H0 (no interaction effect)
#>   Loglikelihood change                           252.17
#>   Difference test (D)                            504.33
#>   Degrees of freedom (D)                              1
#>   P-value (D)                                     0.000
#>  
#> R-Squared:
#>   Y                                               0.470
#> R-Squared Null-Model (H0):
#>   Y                                               0.320
#> R-Squared Change:
#>   Y                                               0.150
#> 
#> Parameter Estimates:
#>   Coefficients                           unstandardized
#>   Information                                  observed
#>   Standard errors                              standard
#>  
#> Latent Variables:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   X =~ 
#>     x1               1.000                             
#>   Z =~ 
#>     z1               1.000                             
#>   Y =~ 
#>     y1               1.000                             
#> 
#> Regressions:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   Y ~ 
#>     X                0.605      0.028    21.26    0.000
#>     Z                0.490      0.028    17.55    0.000
#>     X:Z              0.544      0.023    23.95    0.000
#> 
#> Intercepts:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     x1               1.023      0.024    42.83    0.000
#>     z1               1.011      0.024    41.56    0.000
#>     y1               1.066      0.034    31.64    0.000
#>     Y                0.000                             
#>     X                0.000                             
#>     Z                0.000                             
#> 
#> Covariances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   X ~~ 
#>     Z                0.210      0.026     7.95    0.000
#> 
#> Variances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     x1               0.000                             
#>     z1               0.000                             
#>     y1               0.000                             
#>     X                1.141      0.036    31.62    0.000
#>     Z                1.184      0.037    31.62    0.000
#>     Y                1.399      0.044    31.62    0.000