Skip to content

Commit 7504b4e

Browse files
authored
Harmonize footers (#340)
* Add clearer footnote for special comparisons (#339) * Add clearer footnote for special comparisons Fixes #338 * fix * update snapshot * add tests * lintr * test * Revert "test" This reverts commit 2e5aad5. * minor * fix * fix * revise * fix * simplify * oops * fix * Delete print.new.md * Update get_marginalmeans.R * Update modelbased.Rproj * update snapshots * update snapshots * Update format.R * update snapshots * Update estimate_contrasts.md * Update estimate_means_counterfactuals.md * Update table_footer.R * Update table_footer.R * Update print.md * Update estimate_contrasts.md * fix test * styler
1 parent 7f17252 commit 7504b4e

18 files changed

+424
-315
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.8.9.27
4+
Version: 0.8.9.28
55
Authors@R:
66
c(person(given = "Dominique",
77
family = "Makowski",

R/estimate_contrasts.R

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,12 @@ estimate_contrasts <- function(model,
149149

150150
# Table formatting
151151
attr(out, "table_title") <- c("Marginal Contrasts Analysis", "blue")
152-
attr(out, "table_footer") <- .estimate_means_footer(
152+
attr(out, "table_footer") <- .table_footer(
153153
out,
154-
info$contrast,
154+
by = info$contrast,
155155
type = "contrasts",
156-
p_adjust = p_adjust,
157-
predict = attributes(estimated)$predict,
158-
model_info = insight::model_info(model),
159-
comparison = info$comparison,
160-
datagrid = info$datagrid
156+
model = model,
157+
info = info
161158
)
162159

163160
# Add attributes
@@ -168,10 +165,7 @@ estimate_contrasts <- function(model,
168165
attr(out, "backend") <- backend
169166

170167
# add attributes from workhorse function
171-
attributes(out) <- utils::modifyList(
172-
attributes(out),
173-
info[c("at", "by", "contrast", "predict", "p_adjust", "preserve_range")]
174-
)
168+
attributes(out) <- utils::modifyList(attributes(out), info[.info_elements()])
175169

176170
# Output
177171
class(out) <- c("estimate_contrasts", "see_estimate_contrasts", class(out))

R/estimate_means.R

Lines changed: 5 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,11 @@ estimate_means <- function(model,
156156

157157
# Table formatting
158158
attr(means, "table_title") <- c("Estimated Marginal Means", "blue")
159-
attr(means, "table_footer") <- .estimate_means_footer(
159+
attr(means, "table_footer") <- .table_footer(
160160
means,
161-
type = ifelse(marginalize == "population", "counterfactuals", "means"),
162-
predict = attributes(estimated)$predict,
163-
model_info = insight::model_info(model)
161+
by = info$by,
162+
model = model,
163+
info = info
164164
)
165165

166166
# Add attributes
@@ -171,100 +171,9 @@ estimate_means <- function(model,
171171
attr(means, "coef_name") <- intersect(.valid_coefficient_names(), colnames(means))
172172

173173
# add attributes from workhorse function
174-
attributes(means) <- utils::modifyList(
175-
attributes(means),
176-
info[c("at", "by", "datagrid", "predict", "focal_terms", "preserve_range")]
177-
)
174+
attributes(means) <- utils::modifyList(attributes(means), info[.info_elements()])
178175

179176
# Output
180177
class(means) <- unique(c("estimate_means", class(means)))
181178
means
182179
}
183-
184-
185-
# Table footer ===============================================================
186-
187-
188-
.estimate_means_footer <- function(x,
189-
by = NULL,
190-
type = "means",
191-
p_adjust = NULL,
192-
predict = NULL,
193-
model_info = NULL,
194-
comparison = NULL,
195-
datagrid = NULL) {
196-
table_footer <- switch(type,
197-
counterfactuals = "Average",
198-
"Marginal"
199-
)
200-
table_footer <- paste0("\n", table_footer, " ", type)
201-
202-
# Levels
203-
if (!is.null(by) && length(by) > 0) {
204-
table_footer <- paste0(table_footer, " estimated at ", toString(by))
205-
} else {
206-
table_footer <- paste0(table_footer, " estimated at ", attr(x, "by"))
207-
}
208-
209-
# P-value adjustment footer
210-
if (!is.null(p_adjust) && "p" %in% names(x)) {
211-
if (p_adjust == "none") {
212-
table_footer <- paste0(table_footer, "\np-values are uncorrected.")
213-
} else {
214-
table_footer <- paste0(table_footer, "\np-value adjustment method: ", parameters::format_p_adjust(p_adjust))
215-
}
216-
}
217-
218-
# tell user about scale of predictions / contrasts
219-
if (!is.null(predict) && isFALSE(model_info$is_linear)) {
220-
result_type <- switch(type,
221-
counterfactuals = ,
222-
means = "Predictions",
223-
contrasts = "Contrasts"
224-
)
225-
# exceptions
226-
predict <- switch(predict,
227-
none = "link",
228-
`invlink(link)` = "response",
229-
predict
230-
)
231-
table_footer <- paste0(table_footer, "\n", result_type, " are on the ", predict, "-scale.")
232-
}
233-
234-
# for special hypothesis testing, like "(b1 - b2) = (b4 - b3)", we want to
235-
# add information about the parameter names
236-
if (!is.null(comparison) && is.character(comparison) && grepl("=", comparison, fixed = TRUE) && grepl("\\bb\\d+\\b", comparison)) { # nolint
237-
# find all "b" strings
238-
matches <- gregexpr("\\bb\\d+\\b", comparison)[[1]]
239-
match_lengths <- attr(matches, "match.length")
240-
241-
# extract all "b" strings, so we have a vector of all "b" used in the comparison
242-
parameter_names <- unlist(lapply(seq_along(matches), function(i) {
243-
substr(comparison, matches[i], matches[i] + match_lengths[i] - 1)
244-
}), use.names = FALSE)
245-
246-
# datagrid contains all parameters, so we just need to find out the rows
247-
# and combine column names with row values
248-
if (!is.null(datagrid)) {
249-
# transpose, so we can easier extract information
250-
transposed_dg <- t(datagrid)
251-
# interate over all parameters and create labels with proper names
252-
hypothesis_labels <- unlist(lapply(parameter_names, function(i) {
253-
rows <- as.numeric(sub(".", "", i))
254-
paste0(i, " = ", toString(paste0(colnames(datagrid), " [", transposed_dg[, rows], "]")))
255-
}), use.names = FALSE)
256-
# add all names to the footer
257-
table_footer <- paste0(
258-
table_footer,
259-
"\n",
260-
paste0("Parameters:\n", paste(unlist(hypothesis_labels), collapse = "\n"))
261-
)
262-
}
263-
}
264-
265-
if (all(table_footer == "")) { # nolint
266-
return(NULL)
267-
}
268-
269-
c(paste0(table_footer, "\n"), "blue")
270-
}

R/estimate_predicted.R

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -444,44 +444,18 @@ estimate_relation <- function(model,
444444
attr(out, "focal_terms") <- grid_specs$at_specs$varname
445445
attr(out, "preserve_range") <- grid_specs$preserve_range
446446
attr(out, "table_title") <- c(paste0("Model-based ", tools::toTitleCase(predict)), "blue")
447-
attr(out, "table_footer") <- .estimate_predicted_footer(model, grid_specs, out)
447+
attr(out, "table_footer") <- .table_footer(
448+
out,
449+
by = grid_specs$at,
450+
type = "predictions",
451+
model = model,
452+
info = c(grid_specs, list(predict = predict))
453+
)
454+
448455
attributes(out) <- c(attributes(out), grid_specs[!names(grid_specs) %in% names(attributes(out))])
449456

450457
# Class
451458
class(out) <- c(paste0("estimate_", predict), "estimate_predicted", "see_estimate_predicted", class(out))
452459

453460
out
454461
}
455-
456-
457-
# Utils -------------------------------------------------------------------
458-
459-
#' @keywords internal
460-
.estimate_predicted_footer <- function(model, grid_specs, predictions) {
461-
footer <- paste0("\nVariable predicted: ", insight::find_response(model), "\n")
462-
463-
if ("at" %in% names(grid_specs)) {
464-
footer <- paste0(footer, "Predictors modulated: ", toString(grid_specs$at), "\n")
465-
}
466-
467-
if ("adjusted_for" %in% names(grid_specs) &&
468-
length(grid_specs$adjusted_for) >= 1 &&
469-
!(length(grid_specs$adjusted_for) == 1 && is.na(grid_specs$adjusted_for))) {
470-
# if we have values of adjusted terms, add these here
471-
if (all(grid_specs$adjusted_for %in% colnames(predictions))) {
472-
# get values at which non-focal terms are hold constant
473-
adjusted_values <- sapply(grid_specs$adjusted_for, function(i) {
474-
predictions[[i]][1]
475-
})
476-
# at values to names of non-focal terms (footer)
477-
if (is.numeric(adjusted_values)) {
478-
grid_specs$adjusted_for <- sprintf("%s (%.2g)", grid_specs$adjusted_for, adjusted_values)
479-
} else {
480-
grid_specs$adjusted_for <- sprintf("%s (%s)", grid_specs$adjusted_for, adjusted_values)
481-
}
482-
}
483-
footer <- paste0(footer, "Predictors controlled: ", toString(grid_specs$adjusted_for), "\n")
484-
}
485-
486-
c(footer, "blue")
487-
}

R/estimate_slopes.R

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,7 @@ estimate_slopes <- function(model,
138138
attr(trends, "ci") <- ci
139139

140140
# add attributes from workhorse function
141-
attributes(trends) <- utils::modifyList(
142-
attributes(trends),
143-
info[c("at", "by", "datagrid", "focal_terms", "trend", "coef_name", "preserve_range")]
144-
)
141+
attributes(trends) <- utils::modifyList(attributes(trends), info[.info_elements()])
145142

146143
# Output
147144
class(trends) <- c("estimate_slopes_summary", "estimate_slopes", class(trends))

R/format.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ format.marginaleffects_contrasts <- function(x, model, p_adjust, comparison, ...
231231

232232
# add back new columns
233233
x <- cbind(params[c(contrast, by)], x)
234+
235+
# make sure terms are factors, for data_arrange later
236+
for (i in focal_terms) {
237+
x[[i]] <- factor(x[[i]], levels = unique(x[[i]]))
238+
}
234239
}
235240
}
236241

@@ -315,7 +320,7 @@ format.marginaleffects_contrasts <- function(x, model, p_adjust, comparison, ...
315320
.set_back_attributes <- function(x, formatted_params) {
316321
attributes(formatted_params) <- utils::modifyList(
317322
attributes(formatted_params),
318-
attributes(x)[c("by", "at", "predict", "contrast", "trend", "datagrid", "focal_terms")]
323+
attributes(x)[.info_elements()]
319324
)
320325
formatted_params
321326
}

R/get_emcontrasts.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ get_emcontrasts <- function(model,
6565
attr(out, "at") <- my_args$by
6666
attr(out, "by") <- my_args$by
6767
attr(out, "focal_terms") <- emm_by
68+
attr(out, "p_adjust") <- list(...)$adjust
6869
attr(out, "comparison") <- comparison
6970
out
7071
}

R/get_marginalcontrasts.R

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,18 @@ get_marginalcontrasts <- function(model,
7474
# Last step: Save information in attributes --------------------------------
7575
# ---------------------------------------------------------------------------
7676

77-
attr(out, "contrast") <- my_args$contrast
78-
attr(out, "predict") <- predict
79-
attr(out, "p_adjust") <- p_adjust
80-
attr(out, "at") <- my_args$by
81-
attr(out, "by") <- my_args$by
82-
attr(out, "comparison") <- comparison
77+
out <- .add_attributes(
78+
out,
79+
by = my_args$by,
80+
info = list(
81+
contrast = my_args$contrast,
82+
predict = predict,
83+
comparison = comparison,
84+
marginalize = marginalize,
85+
p_adjust = p_adjust
86+
)
87+
)
88+
8389
class(out) <- unique(c("marginaleffects_contrasts", class(out)))
8490
out
8591
}

R/get_marginalmeans.R

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ get_marginalmeans <- function(model,
5252

5353
# exception: by = NULL computes overall mean
5454
if (is.null(by)) {
55-
datagrid <- at_specs <- NULL
55+
datagrid <- datagrid_info <- NULL
5656
} else {
5757
# setup arguments to create the data grid
5858
dg_args <- list(
@@ -72,7 +72,7 @@ get_marginalmeans <- function(model,
7272

7373
# Get corresponding datagrid (and deal with particular ats)
7474
datagrid <- do.call(insight::get_datagrid, dg_args)
75-
at_specs <- attributes(datagrid)$at_specs
75+
datagrid_info <- attributes(datagrid)
7676

7777
# restore data types - if we have defined numbers in `by`, like
7878
# `by = "predictor = 5"`, and `predictor` was a factor, it is returned as
@@ -109,11 +109,11 @@ get_marginalmeans <- function(model,
109109
if (is.null(datagrid)) {
110110
insight::format_error("Could not create data grid based on variables selected in `by`. Please check if all `by` variables are present in the data set.") # nolint
111111
}
112-
fun_args$variables <- lapply(datagrid, unique)[at_specs$varname]
112+
fun_args$variables <- lapply(datagrid, unique)[datagrid_info$at_specs$varname]
113113
} else {
114114
# all other "marginalizations"
115115
fun_args$newdata <- datagrid
116-
fun_args$by <- at_specs$varname
116+
fun_args$by <- datagrid_info$at_specs$varname
117117
}
118118

119119
# handle distributional parameters
@@ -144,18 +144,51 @@ get_marginalmeans <- function(model,
144144
# Last step: Save information in attributes --------------------------------
145145
# ---------------------------------------------------------------------------
146146

147-
attr(means, "at") <- my_args$by
148-
attr(means, "by") <- my_args$by
149-
attr(means, "focal_terms") <- at_specs$varname
150-
attr(means, "datagrid") <- datagrid
151-
attr(means, "preserve_range") <- attributes(datagrid)$preserve_range
152-
attr(means, "predict") <- predict
147+
means <- .add_attributes(
148+
means,
149+
by = my_args$by,
150+
info = c(
151+
datagrid_info,
152+
list(predict = predict, marginalize = marginalize, datagrid = datagrid)
153+
)
154+
)
153155
class(means) <- unique(c("marginaleffects_means", class(means)))
154156

155157
means
156158
}
157159

158160

161+
# handle attributes -----------------------------------------------------------
162+
163+
#' @keywords internal
164+
.add_attributes <- function(x, by = NULL, info = NULL) {
165+
attr(x, "at") <- by
166+
attr(x, "by") <- by
167+
168+
# compact list
169+
info <- insight::compact_list(info)
170+
171+
if (!is.null(info) && length(info)) {
172+
if (!is.null(info$at_specs$varname)) {
173+
attr(x, "focal_terms") <- info$at_specs$varname
174+
}
175+
for (i in .info_elements()) {
176+
if (!is.null(info[[i]])) {
177+
attr(x, i) <- info[[i]]
178+
}
179+
}
180+
}
181+
x
182+
}
183+
184+
.info_elements <- function() {
185+
c(
186+
"at", "by", "focal_terms", "adjusted_for", "predict", "trend", "comparison",
187+
"contrast", "marginalize", "p_adjust", "datagrid", "preserve_range", "coef_name"
188+
)
189+
}
190+
191+
159192
# Guess -------------------------------------------------------------------
160193

161194
#' @keywords internal

0 commit comments

Comments
 (0)