使用dplyr进行分组操作,结果长度不等于1或组的长度。

16

我不确定要使用哪个函数来完成以下操作:

library(data.table)
dt = data.table(a = 1:4, b = 1:2)

dt[, rep(a[1], 3), by = b]
#   b V1
#1: 1  1
#2: 1  1
#3: 1  1
#4: 2  2
#5: 2  2
#6: 2  2

对于这个长度,summarisemutate都感到不满意:

library(dplyr)
df = data.frame(a = 1:4, b = 1:2)

df %.% group_by(b) %.% summarise(rep(a[1], 3))
#Error: expecting a single value

df %.% group_by(b) %.% mutate(rep(a[1], 3))
#Error: incompatible size (3), expecting 2 (the group size) or 1

不知道是否有帮助,但是使用你的 dplyr 代码与 data.table 结合使用可以实现,而使用 plyrdata.frame 也可以实现。 - dickoa
@dickoa 谢谢,这很有趣(就我来说,这主要是我进行练习,以了解如何使用 dplyr - 我真的不认为将其与 data.table 一起使用有什么意义); 听起来像是 summarise 中的一个 bug。 - eddi
请参见 https://github.com/hadley/dplyr/issues/154。 - hadley
+1 这是一个有趣的差异;希望最终解决方案允许任何组返回任意长度。 - BrodieG
在这种情况下,df %>% group_by(b) %>% slice(rep(1, 3)) 可以正常工作。对于逐行操作,其中每行返回任意数量的值,您可以使用 df %>% mutate(new = map(old, f)) %>% unnest() 的习惯用法。 - Axeman
2个回答

13

dplyr 版本0.2中,您可以使用 do 操作符来实现此操作:

> df %>% group_by(b) %>% do(data.frame(a = rep(.$a[1], 3)))
#Source: local data frame [6 x 2]
#Groups: b
#
#  b a
#1 1 1
#2 1 1
#3 1 1
#4 2 2
#5 2 2
#6 2 2

+1 是为了向我展示 do 可以做什么(尽管请注意我的“答案”中的注释) - BrodieG

7
虽然@beginneR的回答是有效的,但它似乎并不能真正替代data.table的行为。请考虑:
df <- data.frame(a = 1, b = rep(1:1e4, 2))
dt <- data.table(df)
microbenchmark(times=5,
  dt[, rep(a[1], 3), by = b],
  df %>% group_by(b) %>% do(data.frame(a = rep(.$a[1], 3)))
)

dplyr的实现比这个慢了200倍。

Unit: milliseconds
                                                      expr        min         lq     median         uq
                                dt[, rep(a[1], 3), by = b]   13.14318   13.70248   14.60524   15.26676
 df %>% group_by(b) %>% do(data.frame(a = rep(.$a[1], 3))) 3269.40731 3359.11614 3583.19430 3736.67162

也许有更好的方法可以使用do来完成这个任务,而不需要在每个do中调用data.frame。此外,对于在data.table中非常简单的东西,语法有点复杂。

否则,根据Hadley's issue link,看起来这个问题预计将在3.1版的dplyr中实现,这似乎是下一个版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接