simsem / semTools

Useful tools for structural equation modeling
74 stars 36 forks source link

compareFit produces display of length 1, class FitDiff, Mode S4 #121

Open dco67 opened 1 year ago

dco67 commented 1 year ago

Trying to get a comparison of fit using semTools::compareFit produces an output such as:

summary(compareFit(fit.Sal, fit.Reg)) Length Class Mode 1 FitDiff S4

The only way I found to to fix that is to delete the semTools package, and reinstall it... Then it works for a few occasions, before failing again... I have to go through the process a number of times/day!

Is there anything I could to to have a permanent fix on that problem? I know it has something to do with the S4 vs S3 thing, but my competence in R is not up to that point at this time.

Thanks for any help|

PS: I finally found a solution, posted at:
this address

As indicated, I simply add the following function to the environment:

summary.FitDiff<-function(object){ print(object@nested) return(object@fit) }

Working now!

sfcheung commented 1 year ago

Instead of writing a function, this problem can also be solved by loading semTools by library() first to make sure that it is in the search path before calling compareFit(). I adapted the example from the StackOverflow question (the warning message can be ignored).

If semTools::compareFit() is called before library(), the problem persists even library(semTools) is called:

# Call semTools::compareFit(fit.A,fit.B) first and then library(semTools)

data("HolzingerSwineford1939",package="lavaan")
HS.modelA <- ' visual  =~ x1 + x2 + x3
              textual =~ x4 + x5 + x6
              speed   =~ x7 + x8 + x9'

HS.modelB<- ' visual  =~ x1 + x2
              textual =~ x4 + x5 + x6
              speed   =~ x7 + x8 + x9'
fit.A<- lavaan::cfa(HS.modelA, data = HolzingerSwineford1939)
fit.B<- lavaan::cfa(HS.modelB, data = HolzingerSwineford1939)
tmp <- semTools::compareFit(fit.A,fit.B)
#> Warning in (function (object, ..., method = "default", A.method = "delta", :
#> lavaan WARNING: some models are based on a different set of observed variables
summary(tmp)
#>  Length   Class    Mode 
#>       1 FitDiff      S4
library(semTools)
#> Loading required package: lavaan
#> This is lavaan 0.6-15
#> lavaan is FREE software! Please report any bugs.
#> 
#> ###############################################################################
#> This is semTools 0.5-6
#> All users of R (or SEM) are invited to submit functions or ideas for functions.
#> ###############################################################################
summary(tmp)
#>  Length   Class    Mode 
#>       1 FitDiff      S4

Created on 2023-04-16 with reprex v2.0.2

However, the problem will not occur if library(semTools) is called first:

# Call library(semTools) first

library(semTools)
#> Loading required package: lavaan
#> This is lavaan 0.6-15
#> lavaan is FREE software! Please report any bugs.
#> 
#> ###############################################################################
#> This is semTools 0.5-6
#> All users of R (or SEM) are invited to submit functions or ideas for functions.
#> ###############################################################################

data("HolzingerSwineford1939",package="lavaan")
HS.modelA <- ' visual  =~ x1 + x2 + x3
              textual =~ x4 + x5 + x6
              speed   =~ x7 + x8 + x9'

HS.modelB<- ' visual  =~ x1 + x2
              textual =~ x4 + x5 + x6
              speed   =~ x7 + x8 + x9'
fit.A<- lavaan::cfa(HS.modelA, data = HolzingerSwineford1939)
fit.B<- lavaan::cfa(HS.modelB, data = HolzingerSwineford1939)
tmp <- semTools::compareFit(fit.A,fit.B)
#> Warning in (function (object, ..., method = "default", A.method = "delta", :
#> lavaan WARNING: some models are based on a different set of observed variables
summary(tmp)
#> ################### Nested Model Comparison #########################
#> 
#> Chi-Squared Difference Test
#> 
#>       Df    AIC    BIC  Chisq Chisq diff    RMSEA Df diff Pr(>Chisq)   
#> fit.B 17 6662.1 6732.5 61.651                                          
#> fit.A 24 7517.5 7595.3 85.305     23.655 0.088907       7    0.00131 **
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> ####################### Model Fit Indices ###########################
#>         chisq df pvalue rmsea   cfi   tli  srmr       aic       bic
#> fit.B 61.651† 17   .000 .093  .944† .907† .058† 6662.080† 6732.515†
#> fit.A 85.306  24   .000 .092† .931  .896  .065  7517.490  7595.339 
#> 
#> ################## Differences in Fit Indices #######################
#>               df  rmsea    cfi    tli  srmr    aic     bic
#> fit.A - fit.B  7 -0.001 -0.013 -0.011 0.007 855.41 862.824

Created on 2023-04-16 with reprex v2.0.2

Certainly, if library(semTools) is called first, there is no need to use semTools::.

I did not come up with this solution. I vaguely recall this kind of solution has been mentioned somewhere but I could not remember the source.

P.S.: This solution is not ideal because, ideally, a function should behave in the same way whether it is called by pkgname::foo() or foo() after library(pkgname) (assuming no masking). I actually use pkgname::foo() frequently, both in package and in scripts. But the solution above may be sufficient in when using library(semTools) is not an issue.

sfcheung commented 1 year ago

I found the source. The following thread is about a similar problem in blavaan:

https://groups.google.com/g/blavaan/c/KrGzAdzF6QI/m/dGx5xOK4AgAJ

A long term solution may be moving lavaan from Depends to Imports but this may break something, as suggested in the thread.