相对 frequencies/proportions 与 dplyr 创建新列而不是行

Relative frequencies/proportions with dplyr create new columns instead of rows

这个问题的灵感来自this and 问题。

我正在尝试计算每个组中不同值的比例,但我不想为组创建 "new" 行,而是创建新列。

以上面第二个问题为例。如果我有以下数据:

data <- structure(list(value = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L), class = structure(c(1L, 1L, 1L, 
2L, 2L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 1L), .Label = c("A", 
"B"), class = "factor")), .Names = c("value", "class"), class = "data.frame", row.names = c(NA, 
-16L))

我可以计算每个值(1,2,3)在每个class(A,B)中的比例:

data %>%
    group_by(value, class) %>%
    summarise(n = n()) %>%
    complete(class, fill = list(n = 0)) %>%
    group_by(class) %>%
    mutate(freq = n / sum(n))
# A tibble: 6 x 4
  value  class     n      freq
  <int> <fctr> <dbl>     <dbl>
1     1      A     3 0.2727273
2     1      B     3 0.6000000
3     2      A     4 0.3636364
4     2      B     2 0.4000000
5     3      A     4 0.3636364
6     3      B     0 0.0000000

但是我最终为每个 value/class 对添加了一行,而不是我想要这样的东西:

# some code
# A tibble: 6 x 4
   class     n      1        2         3
  <fctr> <dbl>     <dbl>    <dbl>     <dbl>
1    A     11 0.2727273  0.3636364  0.3636364
2    B     5  0.6000000  0.4000000  0.0000000

每组一列。我可以编写 for 循环以从旧数据框构建新数据框,但我确信有更好的方法。有什么建议吗?

谢谢

最后我们可以用pivot_wider

library(dplyr)
library(tidyr)
data %>%
    group_by(value, class) %>%
    summarise(n = n()) %>%
    complete(class, fill = list(n = 0)) %>%
    group_by(class) %>%
    mutate(freq = n / sum(n), n = sum(n)) %>% 
    pivot_wider(names_from = value, values_from = freq)
# A tibble: 2 x 5
# Groups:   class [2]
#  class     n   `1`   `2`   `3`
#  <fct> <dbl> <dbl> <dbl> <dbl>
#1 A        11 0.273 0.364 0.364
#2 B         5 0.6   0.4   0    

或者如@IcecreamToucan 所述,不需要 complete,因为 pivot_wider 可以选择填充自定义值(默认为 NA)

data %>% 
    group_by(value, class) %>% 
    summarise(n = n()) %>%  
    group_by(class) %>%
    mutate(freq = n / sum(n), n = sum(n)) %>% 
    pivot_wider(names_from = value, values_from = freq, values_fill = list(freq = 0))

如果我们使用的是 tidyr 的早期版本,则使用 spread

data %>%
    group_by(value, class) %>%
    summarise(n = n()) %>%
    complete(class, fill = list(n = 0)) %>%
    group_by(class) %>%
    mutate(freq = n / sum(n), n = sum(n)) %>% 
    spread(value, freq)

方法使用 data.table::dcast 而不是 pivot_wider

第 1 行:为每个(值,class)组获取计数(.N),并将其命名为 n

第 2 行:在每个 class 组中创建新变量:

  • N,前面计数的总和
  • pctN的百分比每个n组成

第 3 行:以 classN 作为行,value 作为列名,pct 作为列元素转换为宽,空元素设置为 0.

library(magrittr) # For %>%. Not necessary if dplyr is loaded already
library(data.table)
setDT(data)

data[, .(n = .N), by = .(value, class)] %>% 
    .[, `:=`(N = sum(n), pct = n/sum(n)), by = class] %>% 
  dcast(class + N ~ value, value.var = 'pct', fill = 0)

#    class  N         1         2         3
# 1:     A 11 0.2727273 0.3636364 0.3636364
# 2:     B  5 0.6000000 0.4000000 0.0000000

我们可以用count统计valueclassgroup_byclass的出现次数,计算出频率,得到宽格式的数据.

library(dplyr)
library(tidyr)

data %>%
  count(value, class) %>%
  group_by(class) %>%
  mutate(freq = n/sum(n), n = sum(n)) %>%
  pivot_wider(names_from = value, values_from = freq, values_fill = list(freq = 0))

# class     n   `1`   `2`   `3`
#  <fct> <int> <dbl> <dbl> <dbl>
#1 A        11 0.273 0.364 0.364
#2 B         5 0.6   0.4   0