How do I sum recurring values according to a level in a column and output a table of counts?

时间:2018-06-04 17:10:58

标签: r

I'm new to R and I have data that looks something like this:

categories <- c("A","B","C","A","A","B","C","A","B","C","A","B","B","C","C")
animals <- c("cat","cat","cat","dog","mouse","mouse","rabbit","rat","shark","shark","tiger","tiger","whale","whale","worm")
dat <- cbind(categories,animals)

Some animals repeat according to the category. For example, "cat" appears in all three categories A, B, and C.

I like my new dataframe output to look something like this:

A   B   C   count
1   1   1   1
1   1   0   2
1   0   1   0
0   1   1   2
1   0   0   2
0   1   0   0
0   0   1   2
0   0   0   0

The number 1 under A, B, and C means that the animal appears in that category, 0 means the animal does not appear in that category. For example, the first line has 1s in all three categories. The count is 1 for the first line because "cat" is the only animal that repeats itself in each category.

Is there a function in R that will help me achieve this? Thank you in advance.

4 个答案:

答案 0 :(得分:1)

We can use table to create a cross-tabulation of categories and animals, transpose, convert to data.frame, group_by all categories and count the frequency per combination:

library(dplyr)
library(tidyr)

as.data.frame.matrix(t(table(dat))) %>%
  group_by_all() %>%
  summarize(Count = n())

Result:

# A tibble: 5 x 4
# Groups:   A, B [?]
      A     B     C Count
  <int> <int> <int> <int>
1     0     0     1     2
2     0     1     1     2
3     1     0     0     2
4     1     1     0     2
5     1     1     1     1

Edit (thanks to @C. Braun). Here is how to also include the zero A, B, C combinations:

as.data.frame.matrix(t(table(dat))) %>%
  bind_rows(expand.grid(A = c(0,1), B = c(0,1), C = c(0,1))) %>%
  group_by_all() %>%
  summarize(Count = n()-1) 

or with complete, as suggested by @Ryan:

as.data.frame.matrix(t(table(dat))) %>%
  mutate(non_missing = 1) %>%
  complete(A, B, C) %>%
  group_by(A, B, C) %>%
  summarize(Count = sum(ifelse(is.na(non_missing), 0, 1))) 

Result:

# A tibble: 8 x 4
# Groups:   A, B [?]
      A     B     C Count
  <dbl> <dbl> <dbl> <dbl>
1     0     0     0     0
2     0     0     1     2
3     0     1     0     0
4     0     1     1     2
5     1     0     0     2
6     1     0     1     0
7     1     1     0     2
8     1     1     1     1

答案 1 :(得分:1)

我们有

xxtabs <- function(df, formula) {
    xt <- xtabs(formula, df)
    xxt <- xtabs( ~ . , as.data.frame.matrix(xt))
    as.data.frame(xxt)
}

> xxtabs(dat, ~ animals + categories)
  A B C Freq
1 0 0 0    0
2 1 0 0    2
3 0 1 0    0
4 1 1 0    2
5 0 0 1    2
6 1 0 1    0
7 0 1 1    2
8 1 1 1    1

dat应该真正构建为data.frame(animals, categories))。这种基本方法使用xtabs()来形成第一个交叉表

xt <- xtabs(~ animals + categories, dat)

然后使用as.data.frame.matrix()强制转换为第二个data.frame,并使用计算data.frame

的所有列的第二个交叉列表。
xxt <- xtabs(~ ., as.data.frame.matrix(xt))

强迫所需的表格

as.data.frame(xxt)

我最初说这种方法是“神秘的”,因为它依赖于对as.data.frame()as.data.frame.matrix()之间差异的了解;我认为xtabs()是基础R的用户应该知道的工具。我看到其他解决方案也需要这种神秘的知识,以及更多模糊(例如,complete()group_by_all()funs())部分的知识。此外,其他答案不是(或至少不是以允许的方式编写)容易推广; xxtabs()实际上并不了解传入data.frame的结构,而传入数据的隐含知识存在于其他答案中。

从整洁的方法中学到的一个“教训”是首先放置数据参数,允许管道

dat %>% xxtabs(~ animals + categories)

答案 2 :(得分:0)

If I understood you correctly, this should do the trick.

require(tidyverse)

 dat %>% 
  mutate(value = 1) %>%
  spread(categories, value) %>%
  mutate_if(is.numeric, funs(replace(., is.na(.), 0))) %>% 
  mutate(count = rowSums(data.frame(A, B, C), na.rm = TRUE)) %>%
  group_by(A, B, C) %>%
  summarize(Count = n()) 

# A tibble: 5 x 4
# Groups:   A, B [?]
      A     B     C Count
  <dbl> <dbl> <dbl> <int>
1    0.    0.    1.     2
2    0.    1.    1.     2
3    1.    0.    0.     2
4    1.    1.    0.     2
5    1.    1.    1.     1

答案 3 :(得分:0)

添加data.table解决方案。首先,使用dat将动物与类别联系起来。然后,使用CJ创建A,B,C的组合。将这些组合与dat结合起来,并计算每个组合的出现次数。

dcast(as.data.table(dat), animals ~ categories, length)[
    CJ(A=0:1, B=0:1, C=0:1), .(count=.N), on=c("A","B","C"), by=.EACHI]