How to label columns and retain group sizes when splitting summary table by group?

Viewed 392

When creating a summary table, split by group, the size of each group automatically shows up at the top of their respective columns. So the column headings look like this: Characteristic | 1, N = 100 | 2, N = 120. Code below:

library(dplyr)
library(gtsummary)

data %>% 
  select(group, age, sex) %>%
  tbl_summary(by = group)

However, I would like to name my groups to something more meaningful than "1" and "2". For example, if my data consists of kids in a swim class, I would want to name the groups by the name of the swim class: ducks and turtles. So I do something like this:

library(dplyr)
library(gtsummary)

data %>% 
  select(group, age, sex) %>%
  tbl_summary(by = group) %>%
   modify_header(
    update = list(
      stat_1 ~ "**Ducks**",
      stat_2 ~ "**Turtles**")) 
  modify_spanning_header(
    update = starts_with("stat_") ~ "Swim Class Name") 

This works! However, the size of each group disappears from the top of their respective columns. My work-around is to add in the size of each group manually, as part of the names. I have to leave a little note for myself to check the N for each group before adding it in. Like this:

library(dplyr)
library(gtsummary)

data %>% 
  select(group, age, sex) %>%
  tbl_summary(by = group) %>%
   modify_header(
    update = list(
      stat_1 ~ "**Ducks**, N = 100",
      stat_2 ~ "**Turtles**, N = 120")) %>% # to check the N for each group, remove this to see default appearance which shows the N
  modify_spanning_header(
    update = starts_with("stat_") ~ "Swim Class Name") 

This works but its error-prone as it requires me to double check the numbers then add them in manually.

How do I label the columns, representing each group, AND retain the numbers showing group sizes when splitting the summary table by group?

1 Answers

There are two ways to get this done.

The first is to change the levels in the data frame before you pass it to tbl_summary(). Then the default column header will have your custom headers with the correct Ns by default.

The second is to take advantage dynamic statistics available within modify_header(). When you have a tbl_summary(by=) object split by a variable, you can access {n}, {N}, {p}, and they can be placed in the column header. Review the help file for details: http://www.danieldsjoberg.com/gtsummary/reference/modify.html (Note you need gtsummary v1.3.6 for this code to work.)

Both methods lead to identical tables.

library(gtsummary)
packageVersion("gtsummary")
#> [1] '1.3.6'

# Method 1: Change the underlying data before passing df to `tbl_summary()`
tbl1 <-
  trial %>%
  select(trt, age) %>%
  mutate(trt = factor(trt, labels = c("Duck", "Turtle"))) %>%
  tbl_summary(by = trt, missing = "no")

# Method 2: Use the dynamic stats available in `modify_header()`
tbl2 <-
  trial %>%
  select(trt, age) %>%
  tbl_summary(by = trt, missing = "no") %>%
  modify_header(list(
    stat_1 ~ "**Duck**, N = {n}",
    stat_2 ~ "**Turtle**, N = {n}"
  ))

Created on 2021-01-18 by the reprex package (v0.3.0)

enter image description here

Related