dplyr总结:“.drop = FALSE”等同于保持输出中长度为零的组

当使用plyrddply函数进行summarise时,默认情况下会删除空的类别。 您可以通过添加.drop = FALSE来更改此行为。 但是,在使用dplyr进行summarise时,这不起作用。 是否有另一种方法来保持结果中的空白类别?

这是假数据的例子。

 library(dplyr) df = data.frame(a=rep(1:3,4), b=rep(1:2,6)) # Now add an extra level to df$b that has no corresponding value in df$a df$b = factor(df$b, levels=1:3) # Summarise with plyr, keeping categories with a count of zero plyr::ddply(df, "b", summarise, count_a=length(a), .drop=FALSE) b count_a 1 1 6 2 2 6 3 3 0 # Now try it with dplyr df %.% group_by(b) %.% summarise(count_a=length(a), .drop=FALSE) b count_a .drop 1 1 6 FALSE 2 2 6 FALSE 

不完全是我所希望的。 是否有一个dplyr方法获得与.drop=FALSE相同的结果?

问题仍然是开放的,但在此期间,特别是因为你的数据已经被分解了,你可以使用complete的“tidyr”来获得你可能要找的东西:

 library(tidyr) df %>% group_by(b) %>% summarise(count_a=length(a)) %>% complete(b) # Source: local data frame [3 x 2] # # b count_a # (fctr) (int) # 1 1 6 # 2 2 6 # 3 3 NA 

如果你想重置值为零,你需要指定fill

 df %>% group_by(b) %>% summarise(count_a=length(a)) %>% complete(b, fill = list(count_a = 0)) # Source: local data frame [3 x 2] # # b count_a # (fctr) (dbl) # 1 1 6 # 2 2 6 # 3 3 0 

dplyr解决scheme:

首先进行分组df

 by_b <- tbl_df(df) %>% group_by(b) 

那么我们总结那些以n()

 res <- by_b %>% summarise( count_a = n() ) 

那么我们将结果合并到包含所有因子水平的数据框中:

 expanded_res <- left_join(expand.grid(b = levels(df$b)),res) 

最后,在这种情况下,由于我们正在计数, NA值变为0。

 final_counts <- expanded_res[is.na(expanded_res)] <- 0 

这也可以在function上实现,请参阅答案: 使用dplyr将行添加到分组数据?

黑客:

我以为我会为了这个利益而发表一个可怕的黑客行为。 我真的怀疑你应该真的这样做,但它显示了group_by()如何生成atrributes,就好像df$b是一个字符向量不是一个级别的因素。 此外,我不假装正确理解这一点 – 但我希望这有助于我学习 – 这是我发布的唯一原因!

 by_b <- tbl_df(df) %>% group_by(b) 

定义数据集中不存在的“越界”值。

 oob_val <- nrow(by_b)+1 

修改属性为“trick” summarise()

 attr(by_b, "indices")[[3]] <- rep(NA,oob_val) attr(by_b, "group_sizes")[3] <- 0 attr(by_b, "labels")[3,] <- 3 

做总结:

 res <- by_b %>% summarise(count_a = n()) 

索引并replace所有的oob_val

 res[res == oob_val] <- 0 

这给了预期的:

 > res Source: local data frame [3 x 2] b count_a 1 1 6 2 2 6 3 3 0 

这不是问题中提到的问题,但至less对于这个简单的例子,可以使用xtabs得到相同的结果,例如:

使用dplyr:

 df %.% xtabs(formula = ~ b) %.% as.data.frame() 

或更短:

 as.data.frame(xtabs( ~ b, df)) 

结果(在两种情况下相等):

  b Freq 1 1 6 2 2 6 3 3 0