Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add p0 to OR conversion #659

Merged
merged 10 commits into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
## New features

- `oddsratio_to_d()` and related functions gain a `p0` argument for exact conversion between odds ratios and Cohen's _d_ (thanks @KohlRaphael for the suggestion).
- `interpret*()` now accept (and return) matrices and arrays.

## Breaking Changes

- `interpret_oddsratio()` drops the default `"chen2010"` as it was used incorrectly (thanks to @KohlRaphael).

# effectsize 0.8.9

Expand Down
4 changes: 2 additions & 2 deletions R/convert_between_d_to_r.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ r_to_d <- function(r, n1, n2, ...) {
#' @rdname d_to_r
#' @export
oddsratio_to_d <- function(OR, p0, log = FALSE, ...) {
if (missing(p0)) {
if (missing(p0) || !is.numeric(p0)) {
# Use approximation
if (log) {
log_OR <- OR
Expand All @@ -90,7 +90,7 @@ oddsratio_to_d <- function(OR, p0, log = FALSE, ...) {

odds1 <- OR * probs_to_odds(p0)
p1 <- odds_to_probs(odds1)
qnorm(p1) - qnorm(p0)
stats::qnorm(p1) - stats::qnorm(p0)
}

#' @rdname d_to_r
Expand Down
11 changes: 9 additions & 2 deletions R/interpret.R
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ rules <- function(values, labels = NULL, name = NULL, right = TRUE) {
insight::format_error("Too many labels for the number of reference values!")
}

if (!is.numeric(values)) {
insight::format_error("Reference values must be numeric.")
}

if (length(values) == length(labels) - 1) {
if (is.unsorted(values)) {
insight::format_error("Reference values must be sorted.")
Expand Down Expand Up @@ -129,8 +133,8 @@ is.rules <- function(x) inherits(x, "rules")
#' interpret(eta2, rules = "field2013")
#'
#' X <- chisq.test(mtcars$am, mtcars$cyl == 8)
#' interpret(oddsratio(X), rules = "chen2010")
#' interpret(cramers_v(X), "lovakov2021")
#' interpret(oddsratio(X), rules = "cohen1988")
#' interpret(cramers_v(X), rules = "lovakov2021")
#' @export
interpret <- function(x, ...) {
UseMethod("interpret")
Expand Down Expand Up @@ -159,6 +163,9 @@ interpret.numeric <- function(x, rules, name = attr(rules, "rule_name"),

if (length(x_tran) > 1) {
out <- vapply(x_tran, .interpret, rules = rules, FUN.VALUE = character(1L))
if (is.matrix(x_tran) || is.array(x_tran)) {
out <- structure(out, dim = dim(x_tran), dimnames = dimnames(x_tran))
}
} else {
out <- .interpret(x_tran, rules = rules)
}
Expand Down
10 changes: 5 additions & 5 deletions R/interpret_bf.R
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@ interpret_bf <- function(bf,
)
)

interpretation <- interpret(bf, rules, transform = function(.x) exp(abs(.x)))
interpretation <- interpret(bf, rules, transform = function(.x) exp(ifelse(.x < 0, -.x, .x)))
interpretation[bf == 0] <- "no"

# interpret direction
dir <- interpret(bf, rules(0, c("against", "in favour of")))
dir[bf == 0] <- "against or in favour of"
direction <- interpret(bf, rules(0, c("against", "in favour of")))
direction[bf == 0] <- "against or in favour of"

# Format text
if (include_value) {
bf_fmt <- insight::format_bf(exp(bf), protect_ratio = protect_ratio, exact = exact)
interpretation[] <- sprintf("%s evidence (%s) %s", interpretation, bf_fmt, dir)
interpretation[] <- sprintf("%s evidence (%s) %s", interpretation, bf_fmt, direction)
} else {
interpretation[] <- paste0(interpretation, " evidence ", dir)
interpretation[] <- paste0(interpretation, " evidence ", direction)
}

interpretation[is.na(bf)] <- ""
Expand Down
8 changes: 7 additions & 1 deletion R/interpret_direction.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
#' @examples
#' interpret_direction(.02)
#' interpret_direction(c(.5, -.02))
#' interpret_direction(0)
#'
#' @keywords interpreters
#' @export
interpret_direction <- function(x) {
interpret(x, rules(0, c("negative", "positive"), name = "math", right = FALSE))
interpret(x, rules(0, c("negative", "positive"), name = "math", right = FALSE),
transform = function(.x) {
s <- sign(.x)
replace(s, s == 0, NA_real_)
}
)
}
40 changes: 12 additions & 28 deletions R/interpret_oddsratio.R
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
#' Interpret Odds Ratio
#'
#' @param OR Value or vector of (log) odds ratio values.
#' @param rules Can be "`chen2010"` (default), `"cohen1988"` (through
#' transformation to standardized difference, see [oddsratio_to_d()]) or custom set
#' of [rules()].
#' @param rules If `"cohen1988"` (default), `OR` is transformed to a
#' standardized difference (via [oddsratio_to_d()]) and interpreted according
#' to Cohen's rules (see [interpret_cohens_d()]; see Chen et al., 2010). If a
#' custom set of [rules()] is used, OR is interpreted as is.
#' @param log Are the provided values log odds ratio.
#' @inheritParams interpret
#' @inheritParams oddsratio_to_d
#'
#' @section Rules:
#'
#' Rules apply to OR as ratios, so OR of 10 is as extreme as a OR of 0.1 (1/10).
#'
#' - Chen et al. (2010) (`"chen2010"`; default)
#' - **OR < 1.68** - Very small
#' - **1.68 <= OR < 3.47** - Small
#' - **3.47 <= OR < 6.71** - Medium
#' - **OR >= 6.71 ** - Large
#' - Cohen (1988) (`"cohen1988"`, based on the [oddsratio_to_d()] conversion, see [interpret_cohens_d()])
#' - **OR < 1.44** - Very small
#' - **1.44 <= OR < 2.48** - Small
#' - **2.48 <= OR < 4.27** - Medium
#' - **OR >= 4.27 ** - Large
#' - **OR >= 4.27** - Large
#'
#' @examples
#' interpret_oddsratio(1)
Expand All @@ -40,28 +37,15 @@
#'
#' @keywords interpreters
#' @export
interpret_oddsratio <- function(OR, rules = "chen2010", log = FALSE, ...) {
if (log) {
f_transform <- function(.x) exp(abs(.x))
} else {
f_transform <- function(.x) exp(abs(log(.x)))
}


interpret_oddsratio <- function(OR, rules = "cohen1988", p0 = NULL, log = FALSE, ...) {
if (is.character(rules) && rules == "cohen1988") {
d <- oddsratio_to_d(OR, log = log)
d <- oddsratio_to_d(OR, p0, log = log)
return(interpret_cohens_d(d, rules = rules))
}

rules <- .match.rules(
rules,
list(
chen2010 = rules(c(1.68, 3.47, 6.71), c("very small", "small", "medium", "large"),
name = "chen2010", right = FALSE
),
cohen1988 = NA # for correct error msg
)
)
if (log) {
OR <- exp(OR)
}

interpret(OR, rules, transform = f_transform)
interpret(OR, rules, transform = function(.x) ifelse(.x < 1, 1 / .x, .x))
}
5 changes: 3 additions & 2 deletions R/interpret_rope.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#' Interpretation of
#'
#' @param rope Value or vector of percentages in ROPE.
#' @param ci The Credible Interval (CI) probability, corresponding to the proportion of HDI, that was used. Can be `1` in the case of "full ROPE".
#' @param ci The Credible Interval (CI) probability, corresponding to the
#' proportion of HDI, that was used. Can be `1` in the case of "full ROPE".
#' @param rules A character string (see details) or a custom set of [rules()].
#'
#' @section Rules:
Expand All @@ -29,7 +30,7 @@
#'
#' @keywords interpreters
#' @export
interpret_rope <- function(rope, ci = 0.9, rules = "default") {
interpret_rope <- function(rope, rules = "default", ci = 0.9) {
if (ci < 1) {
e <- .Machine$double.eps

Expand Down
7 changes: 5 additions & 2 deletions R/rank_ANOVA.R
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,12 @@ kendalls_w <- function(x, groups, blocks, data = NULL,

boot_fun <- function(.data, .i) {
split(.data$x, .data$groups) <-
lapply(split(.data$x, .data$groups),
lapply(
split(.data$x, .data$groups),
function(v) {
if (length(v) < 2L) return(v)
if (length(v) < 2L) {
return(v)
}
sample(v, size = length(v), replace = TRUE)
}
)
Expand Down
4 changes: 2 additions & 2 deletions man/interpret.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/interpret_direction.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 8 additions & 12 deletions man/interpret_oddsratio.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions man/interpret_rope.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 26 additions & 2 deletions tests/testthat/test-convert_between.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,35 @@ test_that("exact OR to d", {

expect_equal(cor(oddsratio_to_d(OR), d), 1, tolerance = 0.0001)
expect_equal(oddsratio_to_d(1), 0, tolerance = 0.0001)
expect_equal(oddsratio_to_d(OR, p0), d)
expect_equal(oddsratio_to_d(OR, p0), d, tolerance = 0.0001)

expect_equal(cor(oddsratio_to_r(OR), d_to_r(d)), 1, tolerance = 0.0002)
expect_equal(oddsratio_to_r(1), 0, tolerance = 0.0001)
expect_equal(oddsratio_to_r(OR, p0), d_to_r(d))
expect_equal(oddsratio_to_r(OR, p0), d_to_r(d), tolerance = 0.0001)


# From Chen et al 2010
chen_tab_1 <- as.matrix(
read.table(
text = "p0 OR_1 OR_2 OR_3
0.0100 1.6814 3.4739 6.7128
0.0200 1.6146 3.1332 5.7486
0.0300 1.5733 2.9535 5.2592
0.0400 1.5455 2.8306 4.9471
0.0500 1.5228 2.7416 4.7233
0.0600 1.5060 2.6741 4.5536
0.0700 1.4926 2.6177 4.4191
0.0800 1.4811 2.5707 4.3097
0.0900 1.4709 2.5309 4.2167
0.1000 1.4615 2.4972 4.1387",
header = TRUE
)
)

for (i in seq_len(nrow(chen_tab_1))) {
d_recovered <- oddsratio_to_d(chen_tab_1[i, 2:4], p0 = chen_tab_1[i, 1])
expect_equal(d_recovered, c(0.2, 0.5, 0.8), tolerance = 0.01, ignore_attr = TRUE)
}
})


Expand Down
Loading
Loading