From eaf59e0411285e52b32299f37833b997ce35b3d9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 8 Oct 2026 08:25:35 +0200 Subject: [PATCH 1/5] Add `comparison = "ratio"` as shortcut --- DESCRIPTION | 2 +- NEWS.md | 3 +++ R/estimate_contrasts.R | 5 ++++- R/format.R | 5 +++-- R/get_marginalcontrasts.R | 11 +++++++++-- man/estimate_contrasts.Rd | 5 ++++- man/get_emmeans.Rd | 2 +- 7 files changed, 25 insertions(+), 8 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 10d5a0190..e14b5c72a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: modelbased Title: Estimation of Model-Based Predictions, Contrasts and Means -Version: 0.17.0.8 +Version: 0.17.0.9 Authors@R: c(person(given = "Dominique", family = "Makowski", diff --git a/NEWS.md b/NEWS.md index 71e2f42b3..32a14caf7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -28,6 +28,9 @@ now `predict = "prob"`, which returns the same probabilities as the `"marginaleffects"` backend. +* `comparison = "ratio"` is a new short-cut to compute pairwise comparisons + as ratios. + ## Bug fixes * Fixed issue in `estimate_contrasts()` with wrong assignment of estimates in diff --git a/R/estimate_contrasts.R b/R/estimate_contrasts.R index 05c3c6100..634911b3b 100644 --- a/R/estimate_contrasts.R +++ b/R/estimate_contrasts.R @@ -42,7 +42,7 @@ #' described below, see documentation of [marginaleffects::comparisons], #' [this website](https://marginaleffects.com/bonus/hypothesis.html) and #' section _Comparison options_ below. -#' * String: One of `"pairwise"`, `"revpairwise"`, `"reference"`, +#' * String: One of `"pairwise"`, `"ratio"`, `"revpairwise"`, `"reference"`, #' `"sequential"`, `"meandev"` `"meanotherdev"`, `"poly"`, `"helmert"`, or #' `"trt_vs_ctrl"`. To test multiple hypotheses jointly (usually used for #' factorial designs), `comparison` can also be `"joint"` or `"omnibus"`. In @@ -121,6 +121,9 @@ #' a factor has levels A, B, and C, it would compute A-B, A-C, and B-C. #' - `comparison = "revpairwise"`: Like `"pairwise"`, but reverses the order #' of levels when comparing, e.g. B-A, C-A, and C-B. +#' - `comparison = "ratio"`: This method computes all possible unique +#' ratios between pairs of levels of the focal predictor (not differences, like +#' the default). #' - `comparison = "reference"`: This compares each level of the focal predictor #' to a specified reference level (by default, the first level). For example, #' if levels are A, B, C, and A is the reference, it computes B-A and C-A. diff --git a/R/format.R b/R/format.R index d27b5cf83..bee8ac535 100644 --- a/R/format.R +++ b/R/format.R @@ -307,8 +307,9 @@ format.marginaleffects_contrasts <- function( } # check type of contrast - is_ratio_comparison <- inherits(comparison, "formula") && - identical(deparse(comparison[[2]]), "ratio") + is_ratio_comparison <- (inherits(comparison, "formula") && + identical(deparse(comparison[[2]]), "ratio")) || + identical(comparison, "ratio") # Column name for coefficient - fix needed for contrasting slopes and ratios colnames(x)[colnames(x) == "Slope"] <- "Difference" diff --git a/R/get_marginalcontrasts.R b/R/get_marginalcontrasts.R index 97a142e45..81a1e7381 100644 --- a/R/get_marginalcontrasts.R +++ b/R/get_marginalcontrasts.R @@ -450,8 +450,14 @@ get_marginalcontrasts <- function( } # for some comparisons, we need an empty left-hand side. else, we default # to "difference". - formula_lhs <- switch(comparison, poly = , helmert = "", "difference") - formula_rhs <- comparison + formula_lhs <- switch( + comparison, + poly = , + helmert = "", + ratio = "ratio", + "difference" + ) + formula_rhs <- switch(comparison, ratio = "pairwise", comparison) } if (omnibus_test) { comparison <- NULL @@ -553,6 +559,7 @@ get_marginalcontrasts <- function( .valid_hypothesis_strings <- function() { c( "pairwise", + "ratio", "reference", "sequential", "meandev", diff --git a/man/estimate_contrasts.Rd b/man/estimate_contrasts.Rd index 1067ec14c..847c4f788 100644 --- a/man/estimate_contrasts.Rd +++ b/man/estimate_contrasts.Rd @@ -144,7 +144,7 @@ described below, see documentation of \link[marginaleffects:comparisons]{margina \href{https://marginaleffects.com/bonus/hypothesis.html}{this website} and section \emph{Comparison options} below. \itemize{ -\item String: One of \code{"pairwise"}, \code{"revpairwise"}, \code{"reference"}, +\item String: One of \code{"pairwise"}, \code{"ratio"}, \code{"revpairwise"}, \code{"reference"}, \code{"sequential"}, \code{"meandev"} \code{"meanotherdev"}, \code{"poly"}, \code{"helmert"}, or \code{"trt_vs_ctrl"}. To test multiple hypotheses jointly (usually used for factorial designs), \code{comparison} can also be \code{"joint"} or \code{"omnibus"}. In @@ -402,6 +402,9 @@ differences between pairs of levels of the focal predictor. For example, if a factor has levels A, B, and C, it would compute A-B, A-C, and B-C. \item \code{comparison = "revpairwise"}: Like \code{"pairwise"}, but reverses the order of levels when comparing, e.g. B-A, C-A, and C-B. +\item \code{comparison = "ratio"}: This method computes all possible unique +ratios between pairs of levels of the focal predictor (not differences, like +the default). \item \code{comparison = "reference"}: This compares each level of the focal predictor to a specified reference level (by default, the first level). For example, if levels are A, B, C, and A is the reference, it computes B-A and C-A. diff --git a/man/get_emmeans.Rd b/man/get_emmeans.Rd index 310644bda..0cdc27b8c 100644 --- a/man/get_emmeans.Rd +++ b/man/get_emmeans.Rd @@ -161,7 +161,7 @@ described below, see documentation of \link[marginaleffects:comparisons]{margina \href{https://marginaleffects.com/bonus/hypothesis.html}{this website} and section \emph{Comparison options} below. \itemize{ -\item String: One of \code{"pairwise"}, \code{"revpairwise"}, \code{"reference"}, +\item String: One of \code{"pairwise"}, \code{"ratio"}, \code{"revpairwise"}, \code{"reference"}, \code{"sequential"}, \code{"meandev"} \code{"meanotherdev"}, \code{"poly"}, \code{"helmert"}, or \code{"trt_vs_ctrl"}. To test multiple hypotheses jointly (usually used for factorial designs), \code{comparison} can also be \code{"joint"} or \code{"omnibus"}. In From af2624e922a3e206fd96cbad149a0965330b8883 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 8 Oct 2026 12:23:36 +0200 Subject: [PATCH 2/5] add test --- tests/testthat/test-estimate_contrasts.R | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/testthat/test-estimate_contrasts.R b/tests/testthat/test-estimate_contrasts.R index a08f1b1a3..aec502ae1 100644 --- a/tests/testthat/test-estimate_contrasts.R +++ b/tests/testthat/test-estimate_contrasts.R @@ -1974,3 +1974,23 @@ test_that("estimate_contrast, don't let group labels appear in comparison labels ) ) }) + + +test_that("estimate_contrast, shortcut 'ratio' works", { + skip_if_not_installed("datawizard") + data(stigma, package = "modelbased") + + stigma$symptoms_unreal <- datawizard::recode_into( + symptoms_unreal %in% c("strongly disagree", "disagree") ~ "(strongly) disagree", + symptoms_unreal %in% c("strongly agree", "agree") ~ "(strongly) agree", + data = stigma + ) + + stigma$symptoms_unreal <- as.factor(stigma$symptoms_unreal) + stigma$symptoms_unreal <- relevel(stigma$symptoms_unreal, ref = "(strongly) disagree") + + m <- glm(symptoms_unreal ~ sex, data = stigma, family = binomial()) + out <- estimate_contrasts(m, "sex", comparison = "ratio") + expect_named(out, c("Level1", "Level2", "Ratio", "SE", "CI_low", "CI_high", "z", "p")) + expect_equal(out$Ratio, 6.14634, tolerance = 1e-4) +}) From 15342c162b4c5e5be54fe186de32d5ad37e50f16 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 8 Oct 2026 12:36:14 +0200 Subject: [PATCH 3/5] update docs --- R/estimate_contrasts.R | 13 +++++++------ man/estimate_contrasts.Rd | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/R/estimate_contrasts.R b/R/estimate_contrasts.R index 634911b3b..796d6ce95 100644 --- a/R/estimate_contrasts.R +++ b/R/estimate_contrasts.R @@ -116,14 +116,15 @@ #' #' @section Comparison options: #' -#' - `comparison = "pairwise"`: This method computes all possible unique -#' differences between pairs of levels of the focal predictor. For example, if -#' a factor has levels A, B, and C, it would compute A-B, A-C, and B-C. +#' - `comparison = "pairwise"` (default): This method computes all possible +#' unique differences between pairs of levels of the focal predictor. For +#' example, if a factor has levels A, B, and C, it would compute A-B, A-C, and +#' B-C. The formula notation would be `comparison = difference ~ pairwise` #' - `comparison = "revpairwise"`: Like `"pairwise"`, but reverses the order #' of levels when comparing, e.g. B-A, C-A, and C-B. -#' - `comparison = "ratio"`: This method computes all possible unique -#' ratios between pairs of levels of the focal predictor (not differences, like -#' the default). +#' - `comparison = "ratio"`: This method computes all possible unique ratios +#' between pairs of levels of the focal predictor (not differences, like the +#' default). It is basically a shortcut for `comparison = ratio ~ pairwise`. #' - `comparison = "reference"`: This compares each level of the focal predictor #' to a specified reference level (by default, the first level). For example, #' if levels are A, B, C, and A is the reference, it computes B-A and C-A. diff --git a/man/estimate_contrasts.Rd b/man/estimate_contrasts.Rd index 847c4f788..d928cea97 100644 --- a/man/estimate_contrasts.Rd +++ b/man/estimate_contrasts.Rd @@ -397,14 +397,15 @@ condition (using \code{\link[=estimate_slopes]{estimate_slopes()}}). \section{Comparison options}{ \itemize{ -\item \code{comparison = "pairwise"}: This method computes all possible unique -differences between pairs of levels of the focal predictor. For example, if -a factor has levels A, B, and C, it would compute A-B, A-C, and B-C. +\item \code{comparison = "pairwise"} (default): This method computes all possible +unique differences between pairs of levels of the focal predictor. For +example, if a factor has levels A, B, and C, it would compute A-B, A-C, and +B-C. The formula notation would be \code{comparison = difference ~ pairwise} \item \code{comparison = "revpairwise"}: Like \code{"pairwise"}, but reverses the order of levels when comparing, e.g. B-A, C-A, and C-B. -\item \code{comparison = "ratio"}: This method computes all possible unique -ratios between pairs of levels of the focal predictor (not differences, like -the default). +\item \code{comparison = "ratio"}: This method computes all possible unique ratios +between pairs of levels of the focal predictor (not differences, like the +default). It is basically a shortcut for \code{comparison = ratio ~ pairwise}. \item \code{comparison = "reference"}: This compares each level of the focal predictor to a specified reference level (by default, the first level). For example, if levels are A, B, C, and A is the reference, it computes B-A and C-A. From 07af2ba93982ec15ee0e4a13bc1b80043e0cbf1f Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 8 Oct 2026 12:36:33 +0200 Subject: [PATCH 4/5] missing period. --- R/estimate_contrasts.R | 2 +- man/estimate_contrasts.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/estimate_contrasts.R b/R/estimate_contrasts.R index 796d6ce95..4922db6ba 100644 --- a/R/estimate_contrasts.R +++ b/R/estimate_contrasts.R @@ -119,7 +119,7 @@ #' - `comparison = "pairwise"` (default): This method computes all possible #' unique differences between pairs of levels of the focal predictor. For #' example, if a factor has levels A, B, and C, it would compute A-B, A-C, and -#' B-C. The formula notation would be `comparison = difference ~ pairwise` +#' B-C. The formula notation would be `comparison = difference ~ pairwise`. #' - `comparison = "revpairwise"`: Like `"pairwise"`, but reverses the order #' of levels when comparing, e.g. B-A, C-A, and C-B. #' - `comparison = "ratio"`: This method computes all possible unique ratios diff --git a/man/estimate_contrasts.Rd b/man/estimate_contrasts.Rd index d928cea97..2d7a541ef 100644 --- a/man/estimate_contrasts.Rd +++ b/man/estimate_contrasts.Rd @@ -400,7 +400,7 @@ condition (using \code{\link[=estimate_slopes]{estimate_slopes()}}). \item \code{comparison = "pairwise"} (default): This method computes all possible unique differences between pairs of levels of the focal predictor. For example, if a factor has levels A, B, and C, it would compute A-B, A-C, and -B-C. The formula notation would be \code{comparison = difference ~ pairwise} +B-C. The formula notation would be \code{comparison = difference ~ pairwise}. \item \code{comparison = "revpairwise"}: Like \code{"pairwise"}, but reverses the order of levels when comparing, e.g. B-A, C-A, and C-B. \item \code{comparison = "ratio"}: This method computes all possible unique ratios From b2477e63a07e13e368eeaac9b6867b4d938b6736 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 8 Oct 2026 15:06:43 +0200 Subject: [PATCH 5/5] Fix typo in NEWS.md for comparison shortcut Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 32a14caf7..e6e975aa5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -28,7 +28,7 @@ now `predict = "prob"`, which returns the same probabilities as the `"marginaleffects"` backend. -* `comparison = "ratio"` is a new short-cut to compute pairwise comparisons +* `comparison = "ratio"` is a new shortcut to compute pairwise comparisons as ratios. ## Bug fixes