easystats / performance

:muscle: Models' quality and performance metrics (R2, ICC, LOO, AIC, BF, ...)
https://easystats.github.io/performance/
GNU General Public License v3.0
1k stars 87 forks source link

Cohen's f2 test #197

Open DominiqueMakowski opened 3 years ago

DominiqueMakowski commented 3 years ago

The formula here makes it look at is could be able to compare any nested models that have an R2. But should it be under test_wald(), or a separate test_f2()? The latter would make sense (as test_wald is quite limited), but then @mattansb said the p-value than for the former, so it's roughly equivalent?

m1 <- lm(mpg ~ ., data=mtcars)
m2 <- lm(mpg ~ cyl + vs, data=mtcars)

effectsize::cohens_f_squared(m1, model2 = m2)
#> Loading required namespace: performance
#> Cohen's f2 (partial) |       90% CI | R2_delta
#> ----------------------------------------------
#> 1.07                 | [0.06, 1.79] |     0.14
performance::test_wald(m1, m2)
#>   Name Model df df_diff        F          p
#> 1   m1    lm 21      NA       NA         NA
#> 2   m2    lm 29      -8 2.820169 0.02710374

Created on 2021-02-09 by the reprex package (v0.2.1)

mattansb commented 3 years ago

Assuming we really can compare any nested model, it seems like it becomes really straight forward to do this:

library(performance)
library(parameters)

cohens_f2_from_mods <- function(m1, m2, ci = 0.9) {
  df <- (n_parameters(m1) - n_parameters(m2))
  df_error <- degrees_of_freedom(m1)

  F_val <-
    ((r2(m1)[[1]] - r2(m2)[[1]]) / df) / 
    ((1 - r2(m1)[[1]]) / df_error)

  effectsize::F_to_f2(F_val, df, df_error, ci = ci)
}

cohens_f2_from_wald <- function(wald, ci = 0.9) {
  F_val <- na.omit(wald$`F`)
  df <- na.omit(abs(wald$df_diff))
  df_error <- min(wald$df)
  effectsize::F_to_f2(F_val, df, df_error, ci = ci)
}

m1 <- lm(mpg ~ ., data=mtcars)
m2 <- lm(mpg ~ cyl + vs, data=mtcars)

effectsize::cohens_f_squared(m2, model2 = m1)
#> Cohen's f2 (partial) |       90% CI | R2_delta
#> ----------------------------------------------
#> 1.07                 | [0.06, 1.79] |     0.14

cohens_f2_from_mods(m1, m2)
#> Cohen's f2 (partial) |       90% CI
#> -----------------------------------
#> 1.07                 | [0.06, 1.79]

cohens_f2_from_wald(test_wald(m1, m2))
#> Cohen's f2 (partial) |       90% CI
#> -----------------------------------
#> 1.07                 | [0.06, 1.79]

Created on 2021-02-09 by the reprex package (v1.0.0)

My only concern is: are there cases where cohens_f2_from_wald() and cohens_f2_from_mods() give different results? And if so, which is correct?