42

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

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只是为了澄清一下:我的代码已经使用then完成了我需要它做的事情gather,所以我感兴趣的是 tidyrand中找到更直接的路线dplyr

4

5 回答 5

32

因为dplyr 0.8你可以通过设置参数来做到这.drop = FALSE一点group_by

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
于 2019-02-20T20:41:56.483 回答
31

tidyrcomplete功能就是针对这种情况而设计的。

从文档:

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

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

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
于 2016-06-09T13:57:57.657 回答
4

您可以使用 tidyrexpand来制作因子级别的所有组合,然后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 或任何其他值。这种方式也不是问题的完整解决方案,但它比spread&更快,对 RAM 更友好gather

于 2015-07-01T13:17:09.547 回答
3

plyr具有您正在寻找的功能,但dplyr(还没有),因此您需要一些额外的代码来包含零计数组,如@momeara 所示。另请参阅此问题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
于 2014-09-21T06:18:39.043 回答
2

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

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
于 2014-09-21T06:16:30.520 回答