Repository navigation
Apply by filters to contrasts of slopes with estimate = "average" and the emmeans backend - #694
Merged
Merged
Conversation
…d stop with a clear error when a filter leaves fewer than two slopes
…ope check for custom hypotheses with the emmeans backend
…values that are not levels, and skip the slope count for ordinal models
strengejacke
approved these changes
Oct 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For contrasts of slopes,
estimate_contrasts()applied filter values inbyonly with the defaultestimate. Withestimate = "average"and withbackend = "emmeans", it compared the slopes of all levels and ignored the filter. When a filter left only one slope, the defaultestimatestopped with an error from marginaleffects.Example, with
cylandamas factors inmtcars,m <- lm(mpg ~ wt * cyl * am)andm2 <- lm(mpg ~ wt * cyl):estimate_contrasts(m, "wt", by = c("cyl='4'", "am"))estimate_contrasts(m, "wt", by = c("cyl='4'", "am"), estimate = "average")estimate_contrasts(m, "wt", by = c("cyl='4'", "am"), backend = "emmeans")estimate_contrasts(m2, "wt", by = "cyl='4'")byleaves fewer than two slopes to compareestimate_contrasts(m2, "wt", by = "cyl='4'", estimate = "average")What changed:
get_marginalcontrasts(): forestimate = "average", the slopes are computed on the data rows that pass thebyfilters, so the hypothesis compares only those slopes. Slopes are averaged within eachbygroup, so their values do not change.bykeeps the filter, so the contrast labels show only the filtered levels.get_emcontrasts(): the filter values go intoatforemmeans::emtrends(). Allbyvariables must be factors or character vectors for this. emmeans holds numeric variables at their mean, andatdoes not work for factors made in the formula (factor(cyl)). For these cases the output is the same as on main.R/get_marginalcontrasts.Rparse the filter and drop values that are not levels. If fewer than two slopes remain, they stop with an error. Forestimate = "average", only combinations with data count. Ordinal and multinomial models, and custom hypotheses ("b1 = b2", functions, matrices), skip this check.Tests in the new
test-estimate_contrasts_slopes_filter.Rcompare each result withpairs(emmeans::emtrends(..., at = ...), adjust = "none")at a tolerance of 1e-5. They cover filters on the first or secondbyvariable, with one or two values and with values in reverse order. They use a model with an additive covariate, and they run"typical","average", emmeans and the unfiltered case. They also cover the errors, filters with spaces around=, and filter values that are not levels. The file has noskip_on_os().Not fixed here, the same as on main:
byvariables in contrasts of slopes. Forlm(mpg ~ wt * hp + cyl)withby = "hp", emmeans returns 1 row and marginaleffects returns 45.estimate = "average"and anewdataordataargument, the filters are ignored.estimate, a filter value that is not a level stops with "Unable to compute predicted values"."average", main returned all contrasts here.