cjvanlissa / tidySEM

56 stars 7 forks source link

passing 'auto.fix.first = F' to function add_paths gets rid of equality constraints #74

Open Gootjes opened 1 year ago

Gootjes commented 1 year ago

https://github.com/cjvanlissa/tidySEM/blob/master/R/syntax-add_paths.R#L121-L127

These lines might be the culprit. The implementation seems to drop the equality constraint?

So lavaan sets these two parameters free when auto.fix.first = FALSE, which is correct behavior which is picked up in add_paths, but because of the dropped == the model actually does not constrain them to be equal despite the fact they have identical labels, leading to non-convergence.

auto.fix.first = TRUE does set them to equality because it fixes them all to 1.

library(tidySEM)
#> Loading required package: OpenMx
#> Registered S3 method overwritten by 'tidySEM':
#>   method          from  
#>   predict.MxModel OpenMx

x <- as.data.frame(MASS::mvrnorm(n = 100, 
                   mu = c(0, 0, 0), 
                   Sigma = matrix(c(1.00, 0.60, 0.50, 
                                    0.60, 1.00, 0.70, 
                                    0.50, 0.70, 1.00), 
                                  ncol = 3), empirical = F))

colnames(x) <- c("f_1", "f_2", "f_3")

# Notice the unstandardized parameters are not equal, even though the labels are equal
lavaan::summary(run_lavaan(
  add_paths(tidy_sem(x), 
          c("f =~ f_eq*f_1", "f =~ f_eq*f_2", "f =~ f_eq*f_3"), 
          auto.fix.first = F, 
          std.lv = T)
  ), standardized = T)
#> lavaan 0.6.15 ended normally after 13 iterations
#> 
#>   Estimator                                         ML
#>   Optimization method                           NLMINB
#>   Number of model parameters                         9
#> 
#>   Number of observations                           100
#> 
#> Model Test User Model:
#>                                                       
#>   Test statistic                                 0.000
#>   Degrees of freedom                                 0
#> 
#> Parameter Estimates:
#> 
#>   Standard errors                             Standard
#>   Information                                 Expected
#>   Information saturated (h1) model          Structured
#> 
#> Latent Variables:
#>                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
#>   f =~                                                                  
#>     f_1     (f_eq)    0.603    0.092    6.562    0.000    0.603    0.630
#>     f_2     (f_eq)    0.999    0.097   10.285    0.000    0.999    0.934
#>     f_3     (f_eq)    0.824    0.097    8.509    0.000    0.824    0.795
#> 
#> Intercepts:
#>                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
#>    .f_1               0.123    0.096    1.283    0.199    0.123    0.128
#>    .f_2               0.072    0.107    0.669    0.503    0.072    0.067
#>    .f_3               0.047    0.104    0.457    0.648    0.047    0.046
#>     f                 0.000                               0.000    0.000
#> 
#> Variances:
#>                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
#>    .f_1               0.555    0.088    6.306    0.000    0.555    0.604
#>    .f_2               0.146    0.111    1.316    0.188    0.146    0.128
#>    .f_3               0.395    0.093    4.254    0.000    0.395    0.368
#>     f                 1.000                               1.000    1.000

# Here they are equal, but they are also fixed to `1`
lavaan::summary(run_lavaan(
add_paths(tidy_sem(x), 
          c("f =~ f_eq*f_1", "f =~ f_eq*f_2", "f =~ f_eq*f_3"), 
          auto.fix.first = T)
  ), standardized = T)
#> lavaan 0.6.15 ended normally after 15 iterations
#> 
#>   Estimator                                         ML
#>   Optimization method                           NLMINB
#>   Number of model parameters                         7
#> 
#>   Number of observations                           100
#> 
#> Model Test User Model:
#>                                                       
#>   Test statistic                                12.583
#>   Degrees of freedom                                 2
#>   P-value (Chi-square)                           0.002
#> 
#> Parameter Estimates:
#> 
#>   Standard errors                             Standard
#>   Information                                 Expected
#>   Information saturated (h1) model          Structured
#> 
#> Latent Variables:
#>                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
#>   f =~                                                                  
#>     f_1     (f_eq)    1.000                               0.830    0.754
#>     f_2     (f_eq)    1.000                               0.830    0.831
#>     f_3     (f_eq)    1.000                               0.830    0.814
#> 
#> Intercepts:
#>                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
#>    .f_1               0.123    0.110    1.116    0.264    0.123    0.112
#>    .f_2               0.072    0.100    0.716    0.474    0.072    0.072
#>    .f_3               0.047    0.102    0.464    0.642    0.047    0.046
#>     f                 0.000                               0.000    0.000
#> 
#> Variances:
#>                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
#>    .f_1               0.524    0.094    5.570    0.000    0.524    0.432
#>    .f_2               0.310    0.069    4.492    0.000    0.310    0.310
#>    .f_3               0.351    0.073    4.785    0.000    0.351    0.337
#>     f                 0.690    0.116    5.945    0.000    1.000    1.000

Created on 2023-06-22 with reprex v2.0.2