diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION index f9ec7dee2..2c408c2f4 100644 --- a/CRAN-SUBMISSION +++ b/CRAN-SUBMISSION @@ -1,3 +1,3 @@ -Version: 0.22.0 -Date: 2024-06-19 20:40:00 UTC -SHA: 3861512ee3c11ecca44c2edd412c2a5cb65e1f59 +Version: 0.22.1 +Date: 2024-07-21 11:02:42 UTC +SHA: 109a438b12d4893ae5b2b86aa058923798a6045a diff --git a/DESCRIPTION b/DESCRIPTION index eb54f5beb..81ea45779 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: parameters Title: Processing of Model Parameters -Version: 0.22.0.7 +Version: 0.22.1 Authors@R: c(person(given = "Daniel", family = "Lüdecke", @@ -218,4 +218,3 @@ Config/testthat/edition: 3 Config/testthat/parallel: true Config/Needs/website: easystats/easystatstemplate Config/rcmdcheck/ignore-inconsequential-notes: true -Remotes: easystats/bayestestR diff --git a/NEWS.md b/NEWS.md index 6cd3ccab6..edbe49a36 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,13 @@ # parameters 0.22.1 +## Breaking changes + +* Revised calculation of the second generation p-value (SGPV) in `equivalence_test()`, + which should now be more accurate related to the proportion of the interval + that falls inside the ROPE. Formerly, the confidence interval was simply treated + as uniformly distributed when calculating the SGPV, now the interval is assumed + to be normally distributed. + ## New supported models * Support for `svy2lme` models from package *svylme*. diff --git a/R/equivalence_test.R b/R/equivalence_test.R index 3be162035..f0951e8ac 100644 --- a/R/equivalence_test.R +++ b/R/equivalence_test.R @@ -103,7 +103,8 @@ bayestestR::equivalence_test #' Second generation p-values (SGPV) were proposed as a statistic that #' represents _the proportion of data-supported hypotheses that are also null #' hypotheses_ _(Blume et al. 2018, Lakens and Delacre 2020)_. It represents the -#' proportion of the confidence interval range that is inside the ROPE. +#' proportion of the confidence interval range (assuming a normally distributed, +#' equal-tailed interval) that is inside the ROPE. #' #' ## ROPE range #' Some attention is required for finding suitable values for the ROPE limits @@ -592,10 +593,9 @@ equivalence_test.ggeffects <- function(x, data.frame( CI_low = final_ci[1], CI_high = final_ci[2], - SGPV = .sgpv(range_rope, final_ci), + SGPV = .rope_coverage(range_rope, final_ci), ROPE_low = range_rope[1], ROPE_high = range_rope[2], - # ROPE_Percentage = .rope_coverage(range_rope, final_ci), ROPE_Equivalence = decision, stringsAsFactors = FALSE ) @@ -606,31 +606,34 @@ equivalence_test.ggeffects <- function(x, # helper --------------------- - -.sgpv <- function(rope, ci) { - diff_rope <- abs(diff(rope)) +# this function simply takes the length of the range and calculates the proportion +# of that range that is inside the rope. However, this assumed a "flat", i.e. +# uniformly distributed interval, which is not accurate for standard confidence +# intervals. thus, we no longer use this function, but switch to ".rope_coverage()". +.sgpv <- function(range_rope, ci) { + diff_rope <- abs(diff(range_rope)) diff_ci <- abs(diff(ci)) # inside? - if (min(ci) >= min(rope) && max(ci) <= max(rope)) { + if (min(ci) >= min(range_rope) && max(ci) <= max(range_rope)) { coverage <- 1 # outside? - } else if (max(ci) < min(rope) || min(ci) > max(rope)) { + } else if (max(ci) < min(range_rope) || min(ci) > max(range_rope)) { coverage <- 0 # CI covers completely rope? - } else if (max(ci) > max(rope) && min(ci) < min(rope)) { + } else if (max(ci) > max(range_rope) && min(ci) < min(range_rope)) { coverage <- diff_rope / diff_ci # CI inside rope and outside max rope? - } else if (min(ci) >= min(rope) && max(ci) > max(rope)) { - diff_in_rope <- max(rope) - min(ci) + } else if (min(ci) >= min(range_rope) && max(ci) > max(range_rope)) { + diff_in_rope <- max(range_rope) - min(ci) coverage <- diff_in_rope / diff_ci # CI inside rope and outside min rope? - } else if (max(ci) <= max(rope) && min(ci) < min(rope)) { - diff_in_rope <- max(ci) - min(rope) + } else if (max(ci) <= max(range_rope) && min(ci) < min(range_rope)) { + diff_in_rope <- max(ci) - min(range_rope) coverage <- diff_in_rope / diff_ci } @@ -638,16 +641,27 @@ equivalence_test.ggeffects <- function(x, } -## FIXME make sure this works for different CI levels -.rope_coverage <- function(rope, ci_range, ci) { +# this function simulates a normal distribution, which approximately has the +# same range / limits as the confidence interval, thus indeed representing a +# normally distributed confidence interval. We then calculate the probability +# mass of this interval that is inside the ROPE. +.rope_coverage <- function(range_rope, ci_range) { diff_ci <- abs(diff(ci_range)) out <- bayestestR::distribution_normal( n = 1000, mean = ci_range[2] - (diff_ci / 2), - sd = diff_ci / 3.28 + # we divide the complete range by 2, the one-directional range for the SD + # then, the range from mean value to lower/upper limit, for a normal + # distribution is approximately 3.3 SD (3 SD cover 99.7% of the probability + # mass of the normal distribution). Thus, assuming that half of the ci_range + # refers to ~ 3.3 SD, we "normalize" the value (i.e. divide by 3.29) to get + # the value for one SD, which we need to build the normal distribution. + sd = (diff_ci / 2) / 3.29 ) - rc <- bayestestR::rope(out, range = rope, ci = ci) + # The SGPV refers to the proportion of the confidence interval inside the + # full ROPE - thus, we set ci = 1 here + rc <- bayestestR::rope(out, range = range_rope, ci = 1) rc$ROPE_Percentage } diff --git a/cran-comments.md b/cran-comments.md index 5768f7b84..35e40b5f5 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1 +1 @@ -This release addresses issues with duplicated ORCID in the DESCRIPTION file. +Maintainance release. Furthermore, this release also fixes an issue with the _datawizard_ dependency on Mac OS X with R (old-release). diff --git a/man/equivalence_test.lm.Rd b/man/equivalence_test.lm.Rd index f58df1735..155d2ac51 100644 --- a/man/equivalence_test.lm.Rd +++ b/man/equivalence_test.lm.Rd @@ -149,7 +149,8 @@ practical equivalence and accept the alternative hypothesis. Second generation p-values (SGPV) were proposed as a statistic that represents \emph{the proportion of data-supported hypotheses that are also null hypotheses} \emph{(Blume et al. 2018, Lakens and Delacre 2020)}. It represents the -proportion of the confidence interval range that is inside the ROPE. +proportion of the confidence interval range (assuming a normally distributed, +equal-tailed interval) that is inside the ROPE. } \subsection{ROPE range}{ diff --git a/tests/testthat/_snaps/equivalence_test.md b/tests/testthat/_snaps/equivalence_test.md index 870079898..f8919933a 100644 --- a/tests/testthat/_snaps/equivalence_test.md +++ b/tests/testthat/_snaps/equivalence_test.md @@ -10,8 +10,8 @@ Parameter | 90% CI | SGPV | Equivalence | p ------------------------------------------------------------ (Intercept) | [26.52, 46.86] | < .001 | Rejected | > .999 - gear | [-1.34, 2.07] | 0.354 | Undecided | 0.578 + gear | [-1.34, 2.07] | 0.648 | Undecided | 0.578 wt | [-4.47, -1.57] | < .001 | Rejected | 0.996 - cyl | [-1.94, 0.32] | 0.407 | Undecided | 0.644 + cyl | [-1.94, 0.32] | 0.270 | Undecided | 0.644 hp | [-0.05, 0.01] | > .999 | Accepted | < .001