Search code examples
rexpss

How to create a nested table in R


I'm struggling to figure out how to create the following table;

Image of table

using the following dataset

```{r}
df<-data.frame(ID=c(1,2,3,4,5,6),
       Treat_Cont = c("Treatment", "Treatment", "Treatment", "Control", "Control", "Control"),
       Q1 = c("Yes", "No", NA, "Yes", "No", NA),
       Q2 = c("Yes", "No", NA, "Yes", "No", NA)
       )
```

The main problem I have had using table(), the expss package or tables package is that they treat each level of the factor seperately, so the table will produce a count, for example, for; Treat_Control == Treatment & Q1 == Yes & Q2 == Yes .

Currently, I am at a stage where I'm unsure whether my issue is one of data structure, meaning I should reshape my dataset, or whether I'm missing a function or an argument to achieve this result.

Thanks,


Solution

  • Solution with expss. Not very consise code from my opinion:

    library(expss)
    df = data.frame(ID=c(1,2,3,4,5,6),
                   Treat_Cont = c("Treatment", "Treatment", "Treatment", "Control", "Control", "Control"),
                   Q1 = c("Yes", "No", NA, "Yes", "No", NA),
                   Q2 = c("Yes", "No", NA, "Yes", "No", NA)
    )
    
    df %>% 
        tab_total_row_position("none") %>% # suppress totals
        tab_rows("|" = Treat_Cont) %>%  # "|" suppress var. labels
        tab_cols(total(label = "|")) %>% # "|" suppress var. labels
        # if_na add values for NA
        tab_cells("|" = if_na(Q1, "<NA>")) %>% # "|" suppress var. labels
        tab_stat_cases(label = "Q1") %>% # calculate stats
        tab_cells("|" = if_na(Q1, "<NA>")) %>% # "|" suppress var. labels
        tab_stat_cases(label = "Q2") %>% # calculate stats
        tab_pivot(stat_position = "inside_columns") %>% # labels reposition
        tab_transpose() # transpose table
    

    UPDATE: Shorter solution.

    df %>% 
        calculate(
            cro(Treat_Cont %nest% if_na(Q1, "<NA>"), list("Q1"), total_row_position = "none") %merge%
                cro(Treat_Cont %nest% if_na(Q2, "<NA>"), list("Q2"), total_row_position = "none")
        ) %>% 
        tab_transpose()
    

    Short solution with base R:

    with(df, 
         rbind(
             "Q1" = table(Treat_Cont:addNA(Q1)),
             "Q2" = table(Treat_Cont:addNA(Q2))
         ))