【问题标题】:Proper idiom for adding zero count rows in tidyr/dplyr在 tidyr/dplyr 中添加零计数行的正确习语
【发布时间】:2014-11-15 08:41:56
【问题描述】:

假设我有一些如下所示的计数数据:

library(tidyr)
library(dplyr)

X.raw <- data.frame(
    x = as.factor(c("A", "A", "A", "B", "B", "B")),
    y = as.factor(c("i", "ii", "ii", "i", "i", "i")),
    z = 1:6)
X.raw
#   x  y z
# 1 A  i 1
# 2 A ii 2
# 3 A ii 3
# 4 B  i 4
# 5 B  i 5
# 6 B  i 6

我想这样整理总结一下:

X.tidy <- X.raw %>% group_by(x,y) %>% summarise(count=sum(z))
X.tidy
# Source: local data frame [3 x 3]
# Groups: x
#
#   x  y count
# 1 A  i     1
# 2 A ii     5
# 3 B  i    15

我知道对于x=="B"y=="ii",我们观察到计数为零,而不是缺失值。即现场工作人员实际上在那里,但是因为没有正数,所以没有在原始数据中输入任何行。我可以通过这样做显式添加零计数:

X.fill <- X.tidy %>% spread(y, count, fill=0) %>% gather(y, count, -x)
X.fill
# Source: local data frame [4 x 3]
# 
#   x  y count
# 1 A  i     1
# 2 B  i    15
# 3 A ii     5
# 4 B ii     0

但这似乎有点迂回的做事方式。他们是不是更干净的成语?

澄清一下:我的代码已经完成了我需要它做的事情,使用spread 然后gather,所以我感兴趣的是找到更直接的路线 @987654328 @和dplyr

【问题讨论】:

  • 如果您知道对于“B”/“ii”,观察到的计数为零,为什么源数据集中没有呢?您的源数据集目前表明该组合缺失。
  • 原始数据集仅包含正数。但我们知道所有组合都经过了调查。
  • 您是否有另一个表格显示“x”和“y”的哪些组合都是有效的?不然你打算怎么区分0NA
  • 没有NAs。

标签: r dplyr tidyr


【解决方案1】:

tidyr 中的complete 函数就是为这种情况而设计的。

来自文档:

这是对 expand()、left_join() 和 replace_na 的封装 对于完成缺失的数据组合很有用。

您可以通过两种方式使用它。首先,您可以在汇总之前在原始数据集上使用它,使用 xy 的所有组合“完成”数据集,并用 0 填充 z(您可以使用默认的 NA fill 和在sum 中使用na.rm = TRUE)。

X.raw %>% 
    complete(x, y, fill = list(z = 0)) %>% 
    group_by(x,y) %>% 
    summarise(count = sum(z))

Source: local data frame [4 x 3]
Groups: x [?]

       x      y count
  <fctr> <fctr> <dbl>
1      A      i     1
2      A     ii     5
3      B      i    15
4      B     ii     0

您还可以在预先汇总的数据集上使用complete。请注意,complete 尊重分组。 X.tidy 已分组,因此您可以通过 ungroup 并通过 xy 完成数据集,或者仅列出您希望在每个组中完成的变量 - 在本例中为 y

# Complete after ungrouping
X.tidy %>% 
    ungroup %>%
    complete(x, y, fill = list(count = 0))

# Complete within grouping
X.tidy %>% 
    complete(y, fill = list(count = 0))

每个选项的结果都是一样的:

Source: local data frame [4 x 3]

       x      y count
  <fctr> <fctr> <dbl>
1      A      i     1
2      A     ii     5
3      B      i    15
4      B     ii     0

【讨论】:

    【解决方案2】:

    由于dplyr 0.8你可以通过在group_by中设置参数.drop = FALSE来做到这一点:

    X.tidy <- X.raw %>% group_by(x, y, .drop = FALSE) %>% summarise(count=sum(z))
    X.tidy
    # # A tibble: 4 x 3
    # # Groups:   x [2]
    #   x     y     count
    #   <fct> <fct> <int>
    # 1 A     i         1
    # 2 A     ii        5
    # 3 B     i        15
    # 4 B     ii        0
    

    【讨论】:

      【解决方案3】:

      你可以用tidyr的expand来做因子水平的所有组合,然后left_join

      X.tidy %>% expand(x, y) %>% left_join(X.tidy)
      
      # Joining by: c("x", "y")
      # Source: local data frame [4 x 3]
      # 
      #   x  y count
      # 1 A  i     1
      # 2 A ii     5
      # 3 B  i    15
      # 4 B ii    NA
      

      然后您可以将值保留为 NA 或将它们替换为 0 或任何其他值。 这种方式也不是问题的完整解决方案,但它比spreadgather 更快且对RAM 更友好。

      【讨论】:

      • 另见 tidyr (0.2.0.9000) 开发版中的complete,它是expandleft_joinreplace_na 的便捷包装器。
      • 感谢@aosmith,这正是我所需要的。如果你把它写成答案,我会接受。
      【解决方案4】:

      plyr 具有您正在寻找的功能,但 dplyr 还没有,因此您需要一些额外的代码来包含零计数组,如 @momeara 所示。另见this question。在plyr::ddply 中,您只需添加.drop=FALSE 以在最终结果中保留零计数组。例如:

      library(plyr)
      
      X.tidy = ddply(X.raw, .(x,y), summarise, count=sum(z), .drop=FALSE)
      
      X.tidy
        x  y count
      1 A  i     1
      2 A ii     5
      3 B  i    15
      4 B ii     0
      

      【讨论】:

      • 第二行的意思是 ddply 而不是 dplyr?
      • 是的。谢谢你抓住它!我已经修好了。
      【解决方案5】:

      您可以明确地进行所有可能的组合,然后将其与整洁的摘要结合起来:

      x.fill <- expand.grid(x=unique(x.tidy$x), x=unique(x.tidy$y)) %>%
          left_join(x.tidy, by=("x", "y")) %>%
          mutate(count = ifelse(is.na(count), 0, count)) # replace null values with 0's
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-05
        • 1970-01-01
        • 1970-01-01
        • 2017-01-23
        • 2017-12-09
        • 1970-01-01
        相关资源
        最近更新 更多