Search code examples
rtidyversecrosstab

R: display subtotals in crosstables


For a report I need to create some crosstables with several hierarchies (using r-markdown).

Let's make some fake data:

n <- 100
df <- data.frame(
                 language = sample(c("Ger", "Eng", "Spa"), size = n, replace = TRUE),
                 sex = sample(c("female", "male"), size = n, replace = TRUE),
                 agegrp = sample(c("<=30", ">30"), size = n, replace = TRUE),
                 smoker = sample(c("yes", "no"), size = n, replace = TRUE)
                 )

Now I can create simple crosstables using table() and addmargins() for the totals:

        Agegroup
Language <=30 >30 Sum
     Eng   16  16  32
     Ger   14  13  27
     Spa   17  24  41
     Sum   47  53 100

That's fine, but now I need to create some advanced crosstables with hierarchies. That's why I'm using the ftable()-function. As an example:

> ftable(Language = df$language, Sex = df$sex, Smoker = df$smoker)
                Smoker no yes
Language Sex                 
Eng      female         7   9
         male           7   9
Ger      female         5  11
         male           4   7
Spa      female        12  10
         male          11   8

Is there a way or are there any special packages to calculate the totals or subtotals?

For example I would like to calculate the totals rowwise and/or columnwise:

                Smoker no yes Sum
Language Sex                 
Eng      female         7   9  16
         male           7   9  16
Ger      female         5  11  16
         male           4   7  11
Spa      female        12  10  22
         male          11   8  19
Sum                    46  54 100   

Or is there any function or "grammar" to define which subtotals to calculate? For example:

                Smoker no yes
Language Sex                 
Eng      female         7   9
         male           7   9
         Subtotal      14  18
Ger      female         5  11
         male           4   7
         Subtotal       9  18
Spa      female        12  10
         male          11   8
         Subtotal      23  18

Solution

  • ftable(addmargins(table(df[c('language', 'sex', 'smoker')])))
                    smoker  no yes Sum
    language sex                      
    Eng      female          9  10  19
             male           10   9  19
             Sum            19  19  38
    Ger      female          7   5  12
             male            9   8  17
             Sum            16  13  29
    Spa      female         11   8  19
             male            9   5  14
             Sum            20  13  33
    Sum      female         27  23  50
             male           28  22  50
             Sum            55  45 100
    
    
    
    ftable(addmargins(table(df[c('language', 'sex', 'smoker')]), 2))
                    smoker no yes
    language sex                 
    Eng      female         9  10
             male          10   9
             Sum           19  19
    Ger      female         7   5
             male           9   8
             Sum           16  13
    Spa      female        11   8
             male           9   5
             Sum           20  13