freq table for multiple variables in r

Viewed 1314

I would like to crosstab the items variable vs cat as a frequency table.

df1 <- data.frame(cat =   c(1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4),
                  item1 = c(0,0,1,0,1,1,0,0,0,1,0,1,0,0,1,0,0,1),
                  item2 = c(1,1,0,1,0,1,1,0,0,0,1,0,1,1,0,0,1,0),
                  item3 = c(0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,1,0,1))

> table(df1$cat, df1$item1)
   
    0 1
  1 3 1
  2 3 2
  3 3 2
  4 2 2

Is there a way to print all the items variables freq table by cat together?

Thanks

4 Answers

You can use tally() to get the frequency for every combination of groups.

library(tidyverse)
df1 <- data.frame(cat = c(1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4),
                  item1 = c(0,0,1,0,1,1,0,0,0,1,0,1,0,0,1,0,0,1),
                  item2 = c(1,1,0,1,0,1,1,0,0,0,1,0,1,1,0,0,1,0),
                  item3 = c(0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,1,0,1)) 

df1 %>% mutate_if(is.numeric, as.factor) %>% 
  group_by(cat, item1, item2, item3, .drop=F) %>% 
  tally()

First convert your variables to factors then you can then use group_by(, .drop=F) %>% tally() to tally all of your variables, including all groupings with zero frequencies. Remove .drop=F to remove all zero frequencies.

   cat item1 item2 item3 n
1    1     0     0     0 0
2    1     0     0     1 0
3    1     0     1     0 3
4    1     0     1     1 0
5    1     1     0     0 0
6    1     1     0     1 1
7    1     1     1     0 0
8    1     1     1     1 0
9    2     0     0     0 1
10   2     0     0     1 1
11   2     0     1     0 1
12   2     0     1     1 0
13   2     1     0     0 0
14   2     1     0     1 1
15   2     1     1     0 1
16   2     1     1     1 0
17   3     0     0     0 0
18   3     0     0     1 0
19   3     0     1     0 1
20   3     0     1     1 2
21   3     1     0     0 1
22   3     1     0     1 1
23   3     1     1     0 0
24   3     1     1     1 0
25   4     0     0     0 0
26   4     0     0     1 1
27   4     0     1     0 1
28   4     0     1     1 0
29   4     1     0     0 1
30   4     1     0     1 1
31   4     1     1     0 0
32   4     1     1     1 0

Alternatively, if that is too unwieldy, you can also try table1() from library(table1).

library(tidyverse)
library(table1)
df1 <- data.frame(cat = c(1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4),
                  item1 = c(0,0,1,0,1,1,0,0,0,1,0,1,0,0,1,0,0,1),
                  item2 = c(1,1,0,1,0,1,1,0,0,0,1,0,1,1,0,0,1,0),
                  item3 = c(0,0,1,0,1,0,0,0,1,0,1,1,1,0,0,1,0,1)) 

df1 <- df1 %>% mutate_if(is.numeric, as.factor)

table1(~ item1 + item2 + item3 | cat, data=df1)

To get a table of the frequencies and percentages. The top row is your cat variable.

table1 table

table1() is really great for generating HTML frequency tables. Highly recommend. You can do lots of formatting and labels to make tables presentable. Here is a tutorial

Here is a quick solution in base-R

aggregate(.~ cat, df1, table)

  cat item1.0 item1.1 item2.0 item2.1 item3.0 item3.1
1   1       3       1       1       3       3       1
2   2       3       2       3       2       3       2
3   3       3       2       2       3       2       3
4   4       2       2       3       1       2       2

Here's another approach using ftable and stack from base R:

x <- ftable(cbind(cat = df1[, 1], stack(df1[-1])), row.vars = 1, col.vars = c(3, 2))
x
#     ind    item1   item2   item3  
#     values     0 1     0 1     0 1
# cat                               
# 1              3 1     1 3     3 1
# 2              3 2     3 2     3 2
# 3              3 2     2 3     2 3
# 4              2 2     3 1     2 2

One (debatable) downside of this approach is that the default data.table or data.frame methods for converting ftables to more usable objects will convert the output to a long format. But, you can grab SOfun and use ftable2dt if you want to keep the wide format.

library(SOfun)
ftable2dt(x)
#    cat item1_0 item1_1 item2_0 item2_1 item3_0 item3_1
# 1:   1       3       1       1       3       3       1
# 2:   2       3       2       3       2       3       2
# 3:   3       3       2       2       3       2       3
# 4:   4       2       2       3       1       2       2

You can try this:

List <- list()
for(i in 2:dim(df1)[2])
{
  List[[i-1]] <- table(df1$cat, df1[,i])
}

[[1]]
   
    0 1
  1 3 1
  2 3 2
  3 3 2
  4 2 2

[[2]]
   
    0 1
  1 1 3
  2 3 2
  3 2 3
  4 3 1

[[3]]
   
    0 1
  1 3 1
  2 3 2
  3 2 3
  4 2 2
Related