Skip to content

Commit 65b8f0a

Browse files
committed
mismatch between {emmeans}\s and model_parameters()'s adjusted p-values
Fixes #1103
1 parent 28b7d74 commit 65b8f0a

4 files changed

Lines changed: 129 additions & 33 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: parameters
33
Title: Processing of Model Parameters
4-
Version: 0.28.3.3
4+
Version: 0.28.3.4
55
Authors@R:
66
c(person(given = "Daniel",
77
family = "Lüdecke",

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* Fixed issue where wrong (non-robust) standard errors were calculated for
1818
`coxph` and `svycoxph` objects.
1919

20+
* Fixes issues with Tukey-p-value adjustment for *emmeans* objects.
21+
2022
# parameters 0.28.3
2123

2224
* fixed bug in `standardize_info(<fixest>)` that was preventing

R/format_p_adjust.R

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
format_p_adjust <- function(method) {
1515
method <- tolower(method)
1616

17-
switch(method,
17+
switch(
18+
method,
1819
holm = "Holm (1979)",
1920
hochberg = "Hochberg (1988)",
2021
hommel = "Hommel (1988)",
@@ -68,13 +69,19 @@ format_p_adjust <- function(method) {
6869
} else if (tolower(p_adjust) == "sidak") {
6970
# sidak adjustment
7071
params$p <- 1 - (1 - params$p)^(nrow(params) / rank_adjust)
71-
} else if (tolower(p_adjust) == "sup-t") {
72+
} else if (tolower(p_adjust) == "sup-t") {
7273
# sup-t adjustment
7374
params <- .p_adjust_supt(model, params)
7475
}
7576

76-
if (isTRUE(all(old_p_vals == params$p)) && !identical(p_adjust, "none") && verbose) {
77-
insight::format_warning(paste0("Could not apply ", p_adjust, "-adjustment to p-values. Either something went wrong, or the non-adjusted p-values were already very large.")) # nolint
77+
if (
78+
isTRUE(all(old_p_vals == params$p)) && !identical(p_adjust, "none") && verbose
79+
) {
80+
insight::format_warning(paste0(
81+
"Could not apply ",
82+
p_adjust,
83+
"-adjustment to p-values. Either something went wrong, or the non-adjusted p-values were already very large."
84+
)) # nolint
7885
}
7986
} else if (verbose) {
8087
insight::format_alert(paste0("`p_adjust` must be one of ", toString(all_methods)))
@@ -93,7 +100,10 @@ format_p_adjust <- function(method) {
93100
by_vars <- model@misc$by.vars
94101
if (!is.null(by_vars) && by_vars %in% colnames(params)) {
95102
correction <- insight::n_unique(params[[by_vars]])
103+
} else {
104+
correction <- prod(vapply(model@model.info$xlev, length, numeric(1)))
96105
}
106+
97107
correction
98108
},
99109
error = function(e) {
@@ -106,22 +116,26 @@ format_p_adjust <- function(method) {
106116
# tukey adjustment -----
107117

108118
.p_adjust_tukey <- function(params, stat_column, rank_adjust = 1, verbose = TRUE) {
109-
df_column <- colnames(params)[stats::na.omit(match(c("df", "df_error"), colnames(params)))][1]
119+
df_column <- colnames(params)[stats::na.omit(match(
120+
c("df", "df_error"),
121+
colnames(params)
122+
))][1]
110123
if (!is.na(df_column) && length(stat_column)) {
111124
params$p <- suppressWarnings(stats::ptukey(
112125
sqrt(2) * abs(params[[stat_column]]),
113-
nmeans = nrow(params) / rank_adjust,
126+
nmeans = rank_adjust,
114127
df = params[[df_column]],
115128
lower.tail = FALSE
116129
))
117130
# for specific contrasts, ptukey might fail, and the tukey-adjustement
118131
# could just be simple p-value calculation
119132
if (all(is.na(params$p))) {
120-
params$p <- 2 * stats::pt(
121-
abs(params[[stat_column]]),
122-
df = params[[df_column]],
123-
lower.tail = FALSE
124-
)
133+
params$p <- 2 *
134+
stats::pt(
135+
abs(params[[stat_column]]),
136+
df = params[[df_column]],
137+
lower.tail = FALSE
138+
)
125139
verbose <- FALSE
126140
}
127141
}
@@ -132,7 +146,10 @@ format_p_adjust <- function(method) {
132146
# scheffe adjustment -----
133147

134148
.p_adjust_scheffe <- function(model, params, stat_column, rank_adjust = 1) {
135-
df_column <- colnames(params)[stats::na.omit(match(c("df", "df_error"), colnames(params)))][1]
149+
df_column <- colnames(params)[stats::na.omit(match(
150+
c("df", "df_error"),
151+
colnames(params)
152+
))][1]
136153
if (!is.na(df_column) && length(stat_column)) {
137154
# 1st try
138155
scheffe_ranks <- try(qr(model@linfct)$rank, silent = TRUE)
@@ -146,7 +163,8 @@ format_p_adjust <- function(method) {
146163
scheffe_ranks <- nrow(params)
147164
}
148165
scheffe_ranks <- scheffe_ranks / rank_adjust
149-
params$p <- stats::pf(params[[stat_column]]^2 / scheffe_ranks,
166+
params$p <- stats::pf(
167+
params[[stat_column]]^2 / scheffe_ranks,
150168
df1 = scheffe_ranks,
151169
df2 = params[[df_column]],
152170
lower.tail = FALSE
@@ -182,7 +200,9 @@ format_p_adjust <- function(method) {
182200
# get correlation matrix, based on the covariance matrix
183201
vc <- .safe(stats::cov2cor(insight::get_varcov(model, component = component)))
184202
if (is.null(vc)) {
185-
insight::format_warning("Could not calculate covariance matrix for `sup-t` adjustment.")
203+
insight::format_warning(
204+
"Could not calculate covariance matrix for `sup-t` adjustment."
205+
)
186206
return(params)
187207
}
188208
# get confidence interval level, or set default
@@ -197,18 +217,30 @@ format_p_adjust <- function(method) {
197217
}
198218
# calculate updated confidence interval level, based on simultaenous
199219
# confidence intervals (https://onlinelibrary.wiley.com/doi/10.1002/jae.2656)
200-
crit <- mvtnorm::qmvt(ci_level, df = params[[df_column]][1], tail = "both.tails", corr = vc)$quantile
220+
crit <- mvtnorm::qmvt(
221+
ci_level,
222+
df = params[[df_column]][1],
223+
tail = "both.tails",
224+
corr = vc
225+
)$quantile
201226
# update confidence intervals
202227
params$CI_low <- params$Coefficient - crit * params$SE
203228
params$CI_high <- params$Coefficient + crit * params$SE
204229
# udpate p-values
205230
for (i in 1:nrow(params)) {
206-
params$p[i] <- 1 - mvtnorm::pmvt(
207-
lower = rep(-abs(stats::qt(params$p[i] / 2, df = params[[df_column]][i])), nrow(vc)),
208-
upper = rep(abs(stats::qt(params$p[i] / 2, df = params[[df_column]][i])), nrow(vc)),
209-
corr = vc,
210-
df = params[[df_column]][i]
211-
)
231+
params$p[i] <- 1 -
232+
mvtnorm::pmvt(
233+
lower = rep(
234+
-abs(stats::qt(params$p[i] / 2, df = params[[df_column]][i])),
235+
nrow(vc)
236+
),
237+
upper = rep(
238+
abs(stats::qt(params$p[i] / 2, df = params[[df_column]][i])),
239+
nrow(vc)
240+
),
241+
corr = vc,
242+
df = params[[df_column]][i]
243+
)
212244
}
213245
params
214246
}

tests/testthat/test-p_adjust.R

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ test_that("model_parameters, p-adjust after keep/drop", {
2929
)
3030

3131
expect_message(
32-
mp <- model_parameters(model, include_info = TRUE, keep = c("wt", "hp"), p_adjust = "bonferroni"),
32+
mp <- model_parameters(
33+
model,
34+
include_info = TRUE,
35+
keep = c("wt", "hp"),
36+
p_adjust = "bonferroni"
37+
),
3338
"more than 1 element"
3439
)
3540
expect_equal(
@@ -40,7 +45,12 @@ test_that("model_parameters, p-adjust after keep/drop", {
4045
)
4146

4247
expect_message(
43-
mp <- model_parameters(model, include_info = TRUE, keep = c("cyl", "gear"), p_adjust = "bonferroni"),
48+
mp <- model_parameters(
49+
model,
50+
include_info = TRUE,
51+
keep = c("cyl", "gear"),
52+
p_adjust = "bonferroni"
53+
),
4454
"more than 1 element"
4555
)
4656
expect_equal(
@@ -58,9 +68,26 @@ test_that("model_parameters, emmeans, p-adjust", {
5868
mp <- model_parameters(m)
5969
expect_equal(mp$p, as.data.frame(m)$p.value, tolerance = 1e-4)
6070

61-
m <- pairs(emmeans::emmeans(aov(Sepal.Width ~ Species, data = iris), ~Species), adjust = "scheffe")
71+
m <- pairs(
72+
emmeans::emmeans(aov(Sepal.Width ~ Species, data = iris), ~Species),
73+
adjust = "scheffe"
74+
)
6275
mp <- model_parameters(m, p_adjust = "scheffe")
6376
expect_equal(mp$p, as.data.frame(m)$p.value, tolerance = 1e-4)
77+
78+
m <- pairs(
79+
emmeans::emmeans(aov(Sepal.Width ~ Species, data = iris), ~Species),
80+
adjust = "tukey"
81+
)
82+
mp <- model_parameters(m, p_adjust = "tukey")
83+
expect_equal(mp$p, as.data.frame(m)$p.value, tolerance = 1e-4)
84+
85+
data(warpbreaks)
86+
warp.lm <- lm(breaks ~ wool * tension, data = warpbreaks)
87+
88+
myc <- pairs(emmeans::emmeans(warp.lm, ~ wool + tension))
89+
mp <- model_parameters(myc, p_adjust = "tukey")
90+
expect_equal(mp$p, as.data.frame(myc)$p.value, tolerance = 1e-4)
6491
})
6592

6693

@@ -84,7 +111,11 @@ test_that("model_parameters, simultaenous confidence intervals", {
84111
set.seed(123)
85112
mp <- model_parameters(model, p_adjust = "sup-t")
86113
expect_equal(mp$p, c(0, 0.27904, 0, 0, NA, NA), tolerance = 1e-3)
87-
expect_equal(mp$CI_low, c(67.70195, -0.48377, -4.66802, -7.51974, 8.42651, 11.50991), tolerance = 1e-3)
114+
expect_equal(
115+
mp$CI_low,
116+
c(67.70195, -0.48377, -4.66802, -7.51974, 8.42651, 11.50991),
117+
tolerance = 1e-3
118+
)
88119

89120
skip_if_not_installed("glmmTMB")
90121
data("Salamanders", package = "glmmTMB")
@@ -99,18 +130,49 @@ test_that("model_parameters, simultaenous confidence intervals", {
99130
expect_equal(
100131
mp$p,
101132
c(
102-
0.56769, 0.57466, 0.98029, 0.83123, 0.22681, 0.06271, 0.99876,
103-
0.00068, 0.61786, 0.95269, 0.81296, 0.60973, 0.97504, 0.80566,
104-
0.81871, 0.00024, NA, NA
133+
0.56769,
134+
0.57466,
135+
0.98029,
136+
0.83123,
137+
0.22681,
138+
0.06271,
139+
0.99876,
140+
0.00068,
141+
0.61786,
142+
0.95269,
143+
0.81296,
144+
0.60973,
145+
0.97504,
146+
0.80566,
147+
0.81871,
148+
0.00024,
149+
NA,
150+
NA
105151
),
106152
tolerance = 1e-3
107153
)
108154
expect_equal(
109155
mp$CI_low,
110156
c(
111-
-1.6935, -2.6841, -0.45839, -1.30244, -0.14911, -0.01933, -0.76516,
112-
0.4494, -0.77256, -2.41501, -3.08449, -0.87083, -2.50859, -2.91223,
113-
-8.38616, -4.18299, 0.92944, 0.16671
157+
-1.6935,
158+
-2.6841,
159+
-0.45839,
160+
-1.30244,
161+
-0.14911,
162+
-0.01933,
163+
-0.76516,
164+
0.4494,
165+
-0.77256,
166+
-2.41501,
167+
-3.08449,
168+
-0.87083,
169+
-2.50859,
170+
-2.91223,
171+
-8.38616,
172+
-4.18299,
173+
0.92944,
174+
0.16671
114175
),
115-
tolerance = 1e-3)
176+
tolerance = 1e-3
177+
)
116178
})

0 commit comments

Comments
 (0)