Skip to contents

tbl_custom_summary() builds a summary table whose cells are computed by functions you supply: means adjusted for covariates, rates, treatment effects within subgroups, or anything else a function can return. The table has the structure of tbl_summary(), and add_overall(), add_p(), add_n(), add_stat_label(), inline_text() and the styling functions work on it the same way. ratio_summary() and proportion_summary() build ready-made stat_fns functions.

Usage

tbl_custom_summary(
  data,
  by = NULL,
  label = NULL,
  stat_fns,
  statistic,
  digits = NULL,
  type = NULL,
  value = NULL,
  missing = c("ifany", "no", "always"),
  missing_text = "Unknown",
  missing_stat = "{N_miss}",
  include = everything(),
  overall_row = FALSE,
  overall_row_last = FALSE,
  overall_row_label = "Overall"
)

Arguments

data

(data.frame)
A data frame.

by

(selector)
A single column of data. The statistics are stratified by its levels, one column per level. Rows with a missing by value are dropped with a message. Default is NULL.

label

(formula-list)
Variable labels. The default for each variable is its label attribute, or the column name.

stat_fns

(formula-list)
The function computing the statistics of each variable; see the contract below. Required.

statistic

(formula-list)
The statistics shown for each variable, as a string whose curly-brace names are columns of the stat_fns return, e.g. ~"{mean} ({conf.low}, {conf.high})". The missing-data statistics ({N_obs}, {N_miss}, {N_nonmiss}, {p_miss}, {p_nonmiss}) are also available. Required.

digits

(formula-list)
How the statistics are rounded: integers or formatting functions, possibly named by statistic. When not specified, defaults are guessed from each variable's own values, as for a continuous variable; character and date statistics print as they are.

type

(formula-list)
The summary type. Unlike tbl_summary(), "continuous" is accepted for any variable class, since the statistics come from stat_fns.

value

(formula-list)
The level of a variable to show on a single row.

missing, missing_text, missing_stat

As in tbl_summary(): whether and how to show a missing-value row.

include

(selector)
Variables to summarize. Default is everything().

overall_row

(scalar logical)
Whether to add a first row summarizing all observations. Default is FALSE.

overall_row_last

(scalar logical)
Whether to place the overall row last. Default is FALSE.

overall_row_label

(string)
Label of the overall row. Default is "Overall".

Value

A table of class c("tbl_custom_summary", "tbl_summary", "ltsummary").

The stat_fns contract

Each cell calls the variable's stat_fns function with these named arguments, so the function should accept ...:

  • x: for a continuous variable, its non-missing values in the cell; NULL for categorical and dichotomous variables.

  • data: the cell's rows. For a continuous variable, the by-level subset of data without the by column and without rows where the variable is missing. For a categorical variable, the rows of one (by level, variable level) cell, without the by column and the variable's own column; unused factor levels and empty cells are still called, with zero rows.

  • full_data: the full data frame; for categorical variables, without rows where the variable is missing.

  • variable (string): the variable name.

  • by (character): the by column name; for categorical variables the variable's own name is appended, and without by it is character(0) for continuous variables.

  • strata: NULL.

The function must return a one-row data frame; each column becomes a statistic available to statistic under the column's name. (gtsummary 2.5.1 documents type and stat_display arguments, but does not pass them; ltsummary matches what is passed.)

Caution

add_p() tests the row variable against the by variable, ignoring the summarized values; make sure that test answers your question. add_ci() does not work on custom summary tables.

Examples

# Example 1 ----------------------------------
# mean age by tumor grade and treatment
mean_age <- function(data, ...) {
  data.frame(mean_age = mean(data$age, na.rm = TRUE))
}
trial |>
  tbl_custom_summary(
    by = trt,
    include = grade,
    stat_fns = ~mean_age,
    statistic = ~"{mean_age}",
    digits = ~1,
    overall_row = TRUE
  ) |>
  add_overall(last = TRUE)
# Example 2 ---------------------------------- # response rate with its confidence interval trial |> tbl_custom_summary( by = trt, include = c(stage, grade), stat_fns = ~proportion_summary("response", value = 1), statistic = ~"{prop}% ({conf.low}, {conf.high})", digits = ~label_style_percent(digits = 1) )