总结?根据另一列计算列中的出现次数

Summarise? Count occurences in column based on another column

我相信这可能有一个简单的解决方案,但我无法描述我需要做什么(以及因此要搜索的内容)。我想我需要 summarize 函数。我的目标输出在最底部。

我正在尝试计算另一列中每个唯一值之间某个值的出现次数。这是一个示例 df,希望能说明我需要做什么。

library(dplyr)

set.seed(1)
df <- tibble("name" = c(rep("dinah",2),rep("lucy",4),rep("sora",9)),
             "meal" = c(rep(c("chicken","beef","fish"),5)),
             "date" = seq(as.Date("1999/1/1"),as.Date("2000/1/1"),25),
             "num.wins" = sample(0:30)[1:15])

除其他外,我正在尝试使用此数据总结(求和)每个名字的膳食类型。

df
# A tibble: 15 x 4
   name  meal    date       num.wins
   <chr> <chr>   <date>        <int>
 1 dinah chicken 1999-01-01        8
 2 dinah beef    1999-01-26       11
 3 lucy  fish    1999-02-20       16
 4 lucy  chicken 1999-03-17       25
 5 lucy  beef    1999-04-11        5
 6 lucy  fish    1999-05-06       23
 7 sora  chicken 1999-05-31       27
 8 sora  beef    1999-06-25       15
 9 sora  fish    1999-07-20       14
10 sora  chicken 1999-08-14        1
11 sora  beef    1999-09-08        4
12 sora  fish    1999-10-03        3
13 sora  chicken 1999-10-28       13
14 sora  beef    1999-11-22        6
15 sora  fish    1999-12-17       18

我在下面感兴趣的其他计算方面取得了进展:

df %>% 
  group_by(name) %>% 
  summarise(count=n(),
            medianDate=median(date),
            life=(max(date)-min(date)),
            wins=sum(num.wins))

# A tibble: 3 x 5
  name  count medianDate life      wins
  <chr> <int> <date>     <time>   <int>
1 dinah     2 1999-01-13  25 days    19
2 lucy      4 1999-03-29  75 days    69
3 sora      9 1999-09-08 200 days   101

我的目标是为每种食物添加一个额外的列,并在每一行中显示该食物出现次数的总和,如下所示:

  name  count medianDate life      wins  chicken  beef  fish
1 dinah     2 1999-01-13  25 days    19        1     1     0
2 lucy      4 1999-03-29  75 days    69        1     1     2
3 sora      9 1999-09-08 200 days   101        3     3     3

我不完全确定为什么我会得到 life 的时髦格式,但我认为这可以满足您对膳食类型计数的需要。

df %>% 
  group_by(name) %>% 
  summarise(count=n(),
            medianDate=median(date),
            life=(max(date)-min(date)),
            wins=sum(num.wins),
            chicken = sum(meal == "chicken"),
            beef = sum(meal == "beef"),
            fish = sum(meal == "fish"))

# A tibble: 3 x 8
  name  count medianDate life        wins chicken  beef  fish
  <chr> <int> <date>     <time>     <int>   <int> <int> <int>
1 dinah     2 1999-01-13 " 25 days"    19       1     1     0
2 lucy      4 1999-03-29 " 75 days"    69       1     1     2
3 sora      9 1999-09-08 200 days     101       3     3     3

一种选择是在 summarise 中使用 table 作为 list 列,unnest 然后 spread 为 'wide' 格式

library(tidyverse)
df %>% 
  group_by(name) %>%
  summarise(count=n(),
             medianDate=median(date),
             life=(max(date)-min(date)),
             wins=sum(num.wins),
             n = list(enframe(table(meal))) ) %>%
  unnest %>%
  spread(name1, value, fill = 0)
# A tibble: 3 x 8
#  name  count medianDate life      wins  beef chicken  fish
#  <chr> <int> <date>     <time>   <int> <dbl>   <dbl> <dbl>
#1 dinah     2 1999-01-13  25 days    19     1       1     0
#2 lucy      4 1999-03-29  75 days    69     1       1     2
#3 sora      9 1999-09-08 200 days   101     3       3     3

虽然较旧,并且可能处于弃用路径,reshape2::dcast 做得很好:

reshape2::dcast(df, name ~ meal)
#    name beef chicken fish
# 1 dinah    1       1    0
# 2  lucy    1       1    2
# 3  sora    3       3    3

你可以把公式理解为rows ~ columns。默认情况下,它将使用 length 函数聚合列中的值——它准确地给出了你想要的,每个值的计数。

这可以很容易地加入到您的汇总数据中:

df %>% 
  group_by(name) %>% 
  summarise(count=n(),
            medianDate=median(date),
            life=(max(date)-min(date)),
            wins=sum(num.wins)) %>%
  left_join(reshape2::dcast(df, name ~ meal))
# # A tibble: 3 x 8
#   name  count medianDate life      wins  beef chicken  fish
#   <chr> <int> <date>     <time>   <int> <int>   <int> <int>
# 1 dinah     2 1999-01-13  25 days    19     1       1     0
# 2 lucy      4 1999-03-29  75 days    69     1       1     2
# 3 sora      9 1999-09-08 200 days   101     3       3     3