Skip to contents

Accelerated EM and Adaptive Quadrature

By default the LMS approach uses a standard Expectation-Maximization (EM) algorithm to estimate the model parameters, along with a fixed quadrature.

However, it is possible to use an accelerated EM procedure ("EMA") that uses Quasi-Newton and Fisher Scoring optimization steps when needed. It is also possible to use an adaptive quadrature instead of a fixed quadrature. Using the EMA and adaptive quadrature might yield estimates that are closer to results from Mplus.

If the model struggles to converge, you can try using the accelerated EM procedure by setting method = "EMA", and adaptive.quad = TRUE in the modsem() function. Additionally it is possible to tweak these parameters:

  • max.iter: Maximum number of iterations for the EM algorithm (default is 500).
  • max.step: Maximum number of steps used in the Maximization step of the EM algorithm (default is 1).
  • convergence.rel: Relative convergence criterion for the EM algorithm.
  • convergence.abs: Absolute convergence criterion for the EM algorithm.
  • nodes: Number of nodes for numerical integration (default is 24). Increasing this number can improve the accuracy of the estimates, especially for complex models.
  • quad.range: Integration range for quadrature. Smaller ranges means that the integral is more focused.
  • adaptive.quad.tol: Relative tolerance for determining whether a sub-interval of the adaptive quadrature is accurate enough.

Here we can see an example using the TPB_UK dataaset, which is more troublesome to estimate than the simulated TPB dataset.

tpb_uk <- "
# Outer Model (Based on Hagger et al., 2007)
  ATT =~ att3 + att2 + att1 + att4
  SN =~ sn4 + sn2 + sn3 + sn1
  PBC =~ pbc2 + pbc1 + pbc3 + pbc4
  INT =~ int2 + int1 + int3 + int4
  BEH =~ beh3 + beh2 + beh1 + beh4

# Inner Model (Based on Steinmetz et al., 2011)
  INT ~ ATT + SN + PBC
  BEH ~ INT + PBC
  BEH ~ INT:PBC
"

fit <- modsem(tpb_uk, 
              data = TPB_UK, 
              method = "lms", 
              nodes = 32, # Number of nodes for numerical integration
              adaptive.quad = TRUE, # Use adaptive quadrature
              algorithm ="EMA", # Use accelerated EM algorithm
              convergence.abs = 1e-4, # Relative convergence criterion
              convergence.rel = 1e-10, # Relative convergence criterion
              max.iter = 500, # Maximum number of iterations
              max.step = 1, # Maximum number of steps in the maximization step
              adaptive.quad.tol = 1e-4) # Tolerance when building adaptive quadrature
summary(fit)
#> Estimating baseline model (H0)
#> 
#> modsem (version 1.0.9):
#>   Estimator                                         LMS
#>   Optimization method                        EMA-NLMINB
#>   Number of observations                           1169
#>   Number of iterations                              102
#>   Loglikelihood                               -33386.83
#>   Akaike (AIC)                                 66911.65
#>   Bayesian (BIC)                               67261.06
#>  
#> Numerical Integration:
#>   Points of integration (per dim)                    32
#>   Dimensions                                          1
#>   Total points of integration                        32
#>  
#> Fit Measures for H0:
#>   Loglikelihood                                  -35523
#>   Akaike (AIC)                                 71181.74
#>   Bayesian (BIC)                               71526.09
#>   Chi-square                                    5519.01
#>   Degrees of Freedom (Chi-square)                   162
#>   P-value (Chi-square)                            0.000
#>   RMSEA                                           0.168
#>  
#> Comparative fit to H0 (no interaction effect)
#>   Loglikelihood change                          2136.04
#>   Difference test (D)                           4272.09
#>   Degrees of freedom (D)                              1
#>   P-value (D)                                     0.000
#>  
#> R-Squared:
#>   INT                                             0.901
#>   BEH                                             0.920
#> R-Squared Null-Model (H0):
#>   INT                                             0.896
#>   BEH                                             0.867
#> R-Squared Change:
#>   INT                                             0.005
#>   BEH                                             0.053
#> 
#> Parameter Estimates:
#>   Coefficients                           unstandardized
#>   Information                                  observed
#>   Standard errors                              standard
#>  
#> Latent Variables:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   PBC =~ 
#>     pbc2             1.000                             
#>     pbc1             0.857      0.021    41.28    0.000
#>     pbc3             0.934      0.017    55.38    0.000
#>     pbc4             0.817      0.021    39.72    0.000
#>   ATT =~ 
#>     att3             1.000                             
#>     att2             0.965      0.011    86.33    0.000
#>     att1             0.812      0.017    47.19    0.000
#>     att4             0.870      0.019    45.46    0.000
#>   SN =~ 
#>     sn4              1.000                             
#>     sn2              1.313      0.041    32.30    0.000
#>     sn3              1.350      0.041    32.72    0.000
#>     sn1              1.000      0.038    26.60    0.000
#>   INT =~ 
#>     int2             1.000                             
#>     int1             0.970      0.011    92.12    0.000
#>     int3             0.984      0.010    98.44    0.000
#>     int4             0.992      0.009   104.57    0.000
#>   BEH =~ 
#>     beh3             1.000                             
#>     beh2             0.986      0.013    77.73    0.000
#>     beh1             0.814      0.019    42.72    0.000
#>     beh4             0.803      0.019    41.48    0.000
#> 
#> Regressions:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>   INT ~ 
#>     PBC              1.038      0.036    29.11    0.000
#>     ATT             -0.059      0.029    -2.03    0.042
#>     SN               0.046      0.032     1.44    0.151
#>   BEH ~ 
#>     PBC              0.391      0.052     7.48    0.000
#>     INT              0.576      0.049    11.80    0.000
#>     PBC:INT          0.141      0.008    17.81    0.000
#> 
#> Intercepts:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     pbc2             3.936      0.054    73.54    0.000
#>     pbc1             3.915      0.054    72.51    0.000
#>     pbc3             3.678      0.052    71.25    0.000
#>     pbc4             3.723      0.053    70.83    0.000
#>     att3             3.653      0.055    66.49    0.000
#>     att2             3.771      0.053    70.80    0.000
#>     att1             4.153      0.054    76.80    0.000
#>     att4             3.628      0.059    61.79    0.000
#>     sn4              4.463      0.048    92.12    0.000
#>     sn2              4.299      0.050    86.73    0.000
#>     sn3              4.337      0.050    87.19    0.000
#>     sn1              4.432      0.049    90.11    0.000
#>     int2             3.638      0.054    67.09    0.000
#>     int1             3.786      0.054    70.04    0.000
#>     int3             3.657      0.054    67.47    0.000
#>     int4             3.700      0.054    68.39    0.000
#>     beh3             2.572      0.066    38.87    0.000
#>     beh2             2.491      0.066    37.85    0.000
#>     beh1             2.468      0.066    37.43    0.000
#>     beh4             2.612      0.066    39.60    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              3.719      0.145    25.73    0.000
#>     SN               1.962      0.104    18.78    0.000
#>   ATT ~~ 
#>     SN               1.698      0.101    16.90    0.000
#> 
#> Variances:
#>                   Estimate  Std.Error  z.value  P(>|z|)
#>     pbc2             0.690      0.043    16.17    0.000
#>     pbc1             1.459      0.069    21.03    0.000
#>     pbc3             0.799      0.042    18.86    0.000
#>     pbc4             1.464      0.069    21.27    0.000
#>     att3             0.296      0.023    12.81    0.000
#>     att2             0.306      0.022    13.81    0.000
#>     att1             1.285      0.057    22.58    0.000
#>     att4             1.583      0.071    22.42    0.000
#>     sn4              1.363      0.065    21.03    0.000
#>     sn2              0.491      0.032    15.40    0.000
#>     sn3              0.377      0.032    11.89    0.000
#>     sn1              1.445      0.068    21.13    0.000
#>     int2             0.237      0.014    16.98    0.000
#>     int1             0.404      0.020    20.25    0.000
#>     int3             0.334      0.017    19.35    0.000
#>     int4             0.271      0.015    17.92    0.000
#>     beh3             0.456      0.030    15.27    0.000
#>     beh2             0.513      0.031    16.54    0.000
#>     beh1             1.836      0.082    22.30    0.000
#>     beh4             1.917      0.086    22.40    0.000
#>     PBC              4.421      0.171    25.83    0.000
#>     ATT              4.487      0.178    25.21    0.000
#>     SN               1.727      0.117    14.79    0.000
#>     INT              0.496      0.037    13.37    0.000
#>     BEH              0.447      0.034    13.20    0.000