rnest-rtables

Error with rbind when using different dataset for calculating denominator


I need to create a special table and I created it separately by 2 parts, because each of part need to use different denominator. I think if the structure of 2 table trees are same, rbind function should work.

In my dummy code "tbl_recipe1" and "tbl_recipe2" are used N_col as denominator and the structure of table trees are same, but N_col is different.

enter image description here

enter link description here

When I combined those 2 tables together, there is an error.

enter image description here

I know there may be some limitations when we use rbind function to combine 2 tables. I'm not very familiar to use tern and rtables packages. Do you have any suggestions to generate this special table?

library(random.cdisc.data)
library(dplyr)
library(rtables)
library(haven)
library(purrr)
library(stringr)
library(tern)
library(forcats)
library(formatters)

adsl_cdisc1 <- random.cdisc.data::cadsl
adex_cdisc1 <- random.cdisc.data::cadex

adsl_cdisc2 <- dplyr::filter(adsl_cdisc1, SAFFL == "Y") |> 
  dplyr::select(USUBJID, TRT01A) |> 
  dplyr::mutate(
    TRT01A = forcats::fct_inorder(TRT01A)
  )

adex_cdisc2 <- dplyr::select(
  adex_cdisc1, USUBJID, SAFFL, STRATA1, AVISIT) |>
  dplyr::left_join(adsl_cdisc2, by = "USUBJID") |> 
  dplyr::mutate(
    EXP = dplyr::case_when(
      !is.na(AVISIT) ~ "Number of exposed participants",
      TRUE ~ NA_character_
    ),
    STRA = dplyr::case_when(
      STRATA1 == "B" ~ "Number of records with STRATA1 = B by visit",
      TRUE ~ NA_character_
    ),
    SORT = paste(USUBJID, AVISIT)
  ) |> 
  dplyr::filter(SAFFL == "Y", !is.na(AVISIT))
  
adex_cdisc3 <- dplyr::filter(adex_cdisc1, SAFFL == "Y") |>
  dplyr::select(USUBJID, AVISIT) |>
  dplyr::right_join(adsl_cdisc2, by = "USUBJID") |> 
  dplyr::mutate(
    SORT = paste(USUBJID, AVISIT)
  ) |> 
  distinct(SORT, TRT01A)

tbl_recipe1 <- basic_table() |> 
  add_colcounts() |>
  split_cols_by("TRT01A") |> 
  count_occurrences("EXP",
                    id = "USUBJID",
                    .stats = "count_fraction"
                    ) |>
  rtables::build_table(adex_cdisc2, alt_counts_df = adsl_cdisc2)

tbl_recipe2 <- basic_table() |>
  add_colcounts() |>
  split_cols_by("TRT01A") |>
  count_occurrences("STRA",
                    id = "SORT",
                    .stats = "count_fraction"
                    ) |>
  rtables::build_table(adex_cdisc2, alt_counts_df = adex_cdisc3)

tbl <- rbind(
  tbl_recipe1,
  rtables::rrow(""),
  tbl_recipe2
)

Solution

  • The issue that prevents your two tables from being row-bound is that each table uses a different dataset for alt_counts_df in build_table(). This means that the N values are not the same in both tables, as you can see in the table headers of the screenshots you provided. When using rbind() with two rtables, the column header structures must match exactly.

    You can resolve this error in your table by adding the following line of code after generating both tables but before calling rbind():

    col_info(tbl_recipe2) <- col_info(tbl_recipe1)
    

    This will overwrite the non-matching column information of tbl_recipe2 with the column information of tbl_recipe1 so that both match, with the N values from tbl_recipe1 displayed in the joint table header, but the percentages in the table may not make sense.

    Using the example you provided:

    library(tern)
    
    adsl_cdisc1 <- random.cdisc.data::cadsl
    adex_cdisc1 <- random.cdisc.data::cadex
    
    adsl_cdisc2 <- dplyr::filter(adsl_cdisc1, SAFFL == "Y") |> 
      dplyr::select(USUBJID, TRT01A) |> 
      dplyr::mutate(TRT01A = forcats::fct_inorder(TRT01A))
    
    adex_cdisc2 <- dplyr::select(
      adex_cdisc1, USUBJID, SAFFL, STRATA1, AVISIT) |>
      dplyr::left_join(adsl_cdisc2, by = "USUBJID") |> 
      dplyr::mutate(SORT = paste(USUBJID, AVISIT)) |> 
      dplyr::filter(SAFFL == "Y", !is.na(AVISIT))
    
    adex_cdisc3 <- dplyr::filter(adex_cdisc1, SAFFL == "Y") |>
      dplyr::select(USUBJID, AVISIT) |>
      dplyr::right_join(adsl_cdisc2, by = "USUBJID") |> 
      dplyr::mutate(SORT = paste(USUBJID, AVISIT)) |> 
      dplyr::distinct(SORT, TRT01A)
    
    tbl_recipe1 <- basic_table() |>
      split_cols_by("TRT01A", show_colcounts = TRUE) |>
      summarize_num_patients(
        "USUBJID", 
        .stats = "unique", 
        .labels = "Number of exposed participants"
      ) |>
      build_table(adex_cdisc2, alt_counts_df = adsl_cdisc2)
    
    tbl_recipe2 <- basic_table() |>
      split_cols_by("TRT01A", show_colcounts = TRUE) |>
      count_patients_with_event(
        vars = "SORT",
        filters = c(STRATA1 = "B"),
        .labels = c(count_fraction = "Number of records with STRATA1 = B by visit"),
        denom = "N_col"
      ) |>
      build_table(adex_cdisc2, alt_counts_df = adex_cdisc3)
    
    col_info(tbl_recipe2) <- col_info(tbl_recipe1)
    
    tbl <- rbind(
      tbl_recipe1,
      rrow(""),
      tbl_recipe2
    )
    
    tbl
    #>                                                A: Drug X    C: Combination   B: Placebo 
    #>                                                 (N=134)        (N=132)         (N=134)  
    #> ————————————————————————————————————————————————————————————————————————————————————————
    #> Number of exposed participants                134 (100%)      132 (100%)     134 (100%) 
    #>                                                                                         
    #> Number of records with STRATA1 = B by visit   329 (30.7%)    301 (28.5%)     315 (29.4%)
    

    Created on 2024-11-21 with reprex v2.1.1