Skip to content

Commit 25b2ac5

Browse files
authored
Pairwise comparisons of slopes (#600)
* Pairwise comparisons of slopes Fixes #599 * formatting, use "datasets"
1 parent c269ffb commit 25b2ac5

File tree

9 files changed

+411
-248
lines changed

9 files changed

+411
-248
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: modelbased
33
Title: Estimation of Model-Based Predictions, Contrasts and Means
4-
Version: 0.13.1.8
4+
Version: 0.13.1.9
55
Authors@R:
66
c(person(given = "Dominique",
77
family = "Makowski",

R/estimate_slopes.R

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
#' @examplesIf all(insight::check_if_installed(c("marginaleffects", "emmeans"), quietly = TRUE)) && getRversion() >= "4.5.0"
109109
#' \dontrun{
110110
#' # marginal effects with different `estimate` options
111-
#' data(penguins)
111+
#' data(penguins, package = "datasets")
112112
#' penguins$long_bill <- factor(datawizard::categorize(penguins$bill_len), labels = c("short", "long"))
113113
#' m <- glm(long_bill ~ sex + species + island * bill_dep, data = penguins, family = "binomial")
114114
#'
@@ -121,28 +121,27 @@
121121
#' marginaleffects::avg_slopes(m, variables = "bill_dep", by = "island")
122122
#' }
123123
#' @export
124-
estimate_slopes <- function(model,
125-
trend = NULL,
126-
by = NULL,
127-
predict = NULL,
128-
ci = 0.95,
129-
estimate = NULL,
130-
transform = NULL,
131-
p_adjust = "none",
132-
keep_iterations = FALSE,
133-
backend = NULL,
134-
verbose = TRUE,
135-
...) {
124+
estimate_slopes <- function(
125+
model,
126+
trend = NULL,
127+
by = NULL,
128+
predict = NULL,
129+
ci = 0.95,
130+
estimate = NULL,
131+
transform = NULL,
132+
p_adjust = "none",
133+
keep_iterations = FALSE,
134+
backend = NULL,
135+
verbose = TRUE,
136+
...
137+
) {
136138
# Process argument ---------------------------------------------------------
137139
if (is.null(backend)) {
138140
backend <- getOption("modelbased_backend", "marginaleffects")
139141
}
140142

141143
# validate input
142-
estimate <- insight::validate_argument(
143-
estimate,
144-
c("typical", "specific", "average")
145-
)
144+
estimate <- insight::validate_argument(estimate, c("typical", "specific", "average"))
146145

147146
if (backend == "emmeans") {
148147
# Emmeans ----------------------------------------------------------------

R/p_adjust.R

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,17 @@
88

99
# extract information
1010
datagrid <- attributes(params)$datagrid
11-
focal <- .safe(insight::trim_ws(gsub("=.*", "\\1", attributes(params)$contrast)))
11+
12+
# when contrasting slopes, we need "by" as focal term
13+
if (inherits(params, "estimate_slopes")) {
14+
focal <- .safe(insight::trim_ws(gsub("=.*", "\\1", attributes(params)$by)))
15+
} else {
16+
focal <- .safe(insight::trim_ws(gsub("=.*", "\\1", attributes(params)$contrast)))
17+
}
18+
1219
# extract degrees of freedom
1320
dof <- .safe(params$df[1])
21+
1422
if (is.null(dof)) {
1523
dof <- insight::get_df(model, type = "wald", verbose = FALSE)
1624
}

man/estimate_slopes.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-estimate_contrasts.R

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ test_that("estimate_contrasts - p.adjust", {
703703
skip_if(getRversion() < "4.5.0")
704704
skip_if_not_installed("emmeans")
705705

706-
data(penguins)
706+
data(penguins, package = "datasets")
707707
m_spec <- lm(body_mass ~ species, data = penguins)
708708
out1 <- estimate_contrasts(m_spec, p_adjust = "tukey")
709709
out2 <- estimate_contrasts(m_spec, p_adjust = "tukey", backend = "emmeans")
@@ -1709,7 +1709,7 @@ test_that("estimate_contrast, informative error when `by` and `contrast` are the
17091709

17101710
test_that("estimate_contrast, works with aov (when no statistic is extracted)", {
17111711
skip_if(getRversion() < "4.5.0")
1712-
data(penguins)
1712+
data(penguins, package = "datasets")
17131713
fit <- aov(formula = body_mass ~ species, data = penguins)
17141714

17151715
out1 <- marginaleffects::avg_predictions(fit, by = "species", hypothesis = ~pairwise)
@@ -1736,7 +1736,7 @@ test_that("estimate_contrast, works with aov (when no statistic is extracted)",
17361736
test_that("estimate_contrast, slopes with different estimate options", {
17371737
skip_if(getRversion() < "4.5.0")
17381738
skip_if_not_installed("datawizard")
1739-
data(penguins)
1739+
data(penguins, package = "datasets")
17401740
penguins$long_bill <- factor(
17411741
datawizard::categorize(penguins$bill_len),
17421742
labels = c("short", "long")
@@ -1766,3 +1766,26 @@ test_that("estimate_contrast, comparison-options as strings", {
17661766
out <- estimate_contrasts(mod2, contrast = "cyl_helmert", comparison = "poly")
17671767
expect_equal(out$Difference, c(-8.17673, 0.92996), tolerance = 1e-4)
17681768
})
1769+
1770+
1771+
test_that("estimate_contrast, p-adjust tukey works for contrasting slopes", {
1772+
skip_if(getRversion() < "4.5.0")
1773+
skip_if_not_installed("emmeans")
1774+
1775+
data(penguins, package = "datasets")
1776+
m <- lm(flipper_len ~ body_mass * species, data = penguins)
1777+
1778+
out1 <- as.data.frame(pairs(emmeans::emtrends(m, ~species, var = "body_mass")))
1779+
out2 <- estimate_contrasts(
1780+
m,
1781+
contrast = "body_mass",
1782+
by = "species",
1783+
p_adjust = "tukey"
1784+
)
1785+
1786+
# Note: p-values from emmeans::emtrends() + pairs() and estimate_contrasts()
1787+
# can differ slightly due to different underlying calculation/adjustment
1788+
# methods, especially with Tukey p-adjustment. A tolerance of 1e-2 is used
1789+
# here to avoid fragile tests while still ensuring close agreement.
1790+
expect_equal(out1$p.value, out2$p, tolerance = 1e-2)
1791+
})

0 commit comments

Comments
 (0)