使用group_by(多个变量)时的dplyr问题

58

我希望开始使用dplyr代替ddply,但我不太明白它是如何工作的(我已经阅读了文档)。

例如,为什么当我尝试mutate()时,"group_by"函数不能像预期那样工作?

看一下mtcars:

library(car)

假设我创建一个数据框,它是按"cyl"和"gear"分组的mtcars摘要:

df1 <- mtcars %.%
            group_by(cyl, gear) %.%
            summarise(
                newvar = sum(wt)
            )

接下来我想进一步总结这个数据框。使用ddply方法很简单,但是当我尝试使用dplyr时,并没有真正地“按组分组”:

df2 <- df1 %.%
            group_by(cyl) %.%
            mutate(
                newvar2 = newvar + 5
            )

仍然产生未分组的输出:

  cyl gear newvar newvar2
1   6    3  6.675  11.675
2   4    4 19.025  24.025
3   6    4 12.375  17.375
4   6    5  2.770   7.770
5   4    3  2.465   7.465
6   8    3 49.249  54.249
7   4    5  3.653   8.653
8   8    5  6.740  11.740

我的语法有问题吗?


编辑:

如果我要用plyr和ddply来做这件事:

df1 <- ddply(mtcars, .(cyl, gear), summarise, newvar = sum(wt))

然后获取第二个数据框:

df2 <- ddply(df1, .(cyl), summarise, newvar2 = sum(newvar) + 5)

但是使用相同的方法,在dplyr中 用 sum(newvar) + 5作为 summarise()函数的参数并不能起作用...


1
请问您能否提供使用ddply的等效plyr代码? - dickoa
“ungrouped”是什么意思?您是期望每个组只有一行数据吗?还是期望同一组的所有行都在下面? - flodel
我期望第二个数据框只有三行(每个汽缸一行),因为根据我刚刚添加的ddply参数,它看起来是这样的... 我猜这只是一个我遗漏了的地方需要添加一个参数的问题? - Marc Tulla
3
我认为你混淆了mutatesummarise的概念。 - flodel
2
噢,是这样啊。如果我想在汇总数据框的同时添加新变量,那么总结是否和变异一样有效? - Marc Tulla
5个回答

81

我有过类似的问题。我发现简单地分离plyr就可以解决它:

detach(package:plyr)    
library(dplyr)

13
过去一个半小时里,我一直在这里发愁,试图理解为什么dplyr简单地忽略了我的分组。很高兴知道我不是疯了。 - Brandon Bertelsen
6
我不知道为什么代码在使用 summarize 时可以正常运行,但稍后访问时就无法运行。实际上,在加载 dplyr 后我添加了 plyr,这就是原因。我不确定这是否是最近才发生的情况,但最近在同时加载这两个库时,我注意到了这个问题:你已经在加载了 dplyr 之后又加载了 plyr - 这可能会引起问题。如果你需要同时使用 plyr 和 dplyr 中的函数,请先加载 plyr,然后再加载 dplyr: library(plyr); library(dplyr) - Hendy
1
这种情况经常发生在dplyr方法被重载时。一个通用的解决方案是使用dplyr::summerise(...)显式地引用dplyr版本的方法。 - passerby51

45

进一步说,按照Dickoa的答案来看,正如Hadley所说,“summarise可以将一层分组去掉”。它会从你应用分组的相反顺序中去掉分组,因此你只需使用

mtcars %>%
 group_by(cyl, gear) %>%
 summarise(newvar = sum(wt)) %>%
 summarise(newvar2 = sum(newvar) + 5)

请注意,在第二行使用 group_by(gear, cyl) 会得到不同的答案。

为了使你的第一次尝试起作用:

df1 <- mtcars %>%
 group_by(cyl, gear) %>%
 summarise(newvar = sum(wt))

df2 <- df1 %>%
 group_by(cyl) %>%
 summarise(newvar2 = sum(newvar)+5)

16
我仍然希望能够获得有关哈德利的“剥落”隐喻的更好信息。是否有人可以提供一些相关的参考资料或已发布的答案? - Michael Bellhouse
2
请查看 https://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html ,查看包含“每个汇总剥离一个分组级别”的部分。 - Alex

11

如果你使用summarise而不是mutate将你的plyr代码转换成dplyr,你会得到相同的结果。

library(plyr)
df1 <- ddply(mtcars, .(cyl, gear), summarise, newvar = sum(wt))
df2 <- ddply(df1, .(cyl), summarise, newvar2 = sum(newvar) + 5)
df2
##   cyl newvar2
## 1   4  30.143
## 2   6  26.820
## 3   8  60.989

detach(package:plyr)    
library(dplyr)
mtcars %.%
    group_by(cyl, gear) %.%
    summarise(newvar = sum(wt)) %.%
    group_by(cyl) %.%
    summarise(newvar2 = sum(newvar) + 5)
##   cyl newvar2
## 1   4  30.143
## 2   8  60.989
## 3   6  26.820

编辑

由于summarise会丢弃最后一组(gear),因此您可以跳过第二个group_by(请参见下面@hadley的评论)。

library(dplyr)
mtcars %.%
    group_by(cyl, gear) %.%
    summarise(newvar = sum(wt)) %.%
    summarise(newvar2 = sum(newvar) + 5)
##   cyl newvar2
## 1   4  30.143
## 2   8  60.989
## 3   6  26.820

那么第二个“group_by()”和“summarise()”调用会覆盖第一个吗? - Marc Tulla
1
是的,您还可以使用regroup来强制执行。 - dickoa
2
你不需要第二个 group_by(),因为 summarise 会自动删除最后一个分组(即它折叠的分组)。 - hadley
感谢 @hadley 我不知道这个特性。 - dickoa
如果出于某种原因您不想分离plyr,您可以在group_bysummarize函数前面指定dplyr:: - pyll

6

解除 plyr 的依赖关系是解决问题的一种方式,这样您就可以根据需要使用 dplyr 函数...但是如果您需要使用来自 plyr 的其他函数来完成代码中的其他任务呢?

(在此示例中,我已加载了 dplyrplyr 库)

假设我们有一个简单的数据框,并且我们想要计算按不同级别的 gname 分组时变量 value 的组内总和。

> dx<-data.frame(gname=c(1,1,1,2,2,2,3,3,3), value = c(2,2,2,4,4,4,5,6,7))
> dx
  gname value
1     1     2
2     1     2
3     1     2
4     2     4
5     2     4
6     2     4
7     3     5
8     3     6
9     3     7

但是当我们尝试使用我们相信会产生dplyr分组求和的方法时,就会出现以下情况:

dx %>% group_by(gname) %>% mutate(mysum=sum(value))
Source: local data frame [9 x 3]
Groups: gname

  gname value mysum
1     1     2    36
2     1     2    36
3     1     2    36
4     2     4    36
5     2     4    36
6     2     4    36
7     3     5    36
8     3     6    36
9     3     7    36

可能是由于dplyrplyr之间的group_bymutate函数之间的一些交互或超载导致它没有给出我们想要的答案。我们可以将plyr分离,但另一种方法是为dplyr版本的group_bymutate提供独特的调用:

dx %>% dplyr::group_by(gname) %>% dplyr::mutate(mysum=sum(value))
Source: local data frame [9 x 3]
Groups: gname

  gname value mysum
1     1     2     6
2     1     2     6
3     1     2     6
4     2     4    12
5     2     4    12
6     2     4    12
7     3     5    18
8     3     6    18
9     3     7    18

现在我们看到这个按预期工作了。

5

dplyr在您的示例中表现正常。按照您指定的方式,mutate只会在创建newvar2时将5添加到newvar的每个值。无论您是否分组,结果都是相同的。但是,如果您指定了一些按组别不同的内容,则会得到不同的结果。例如:

df1 %.%
            group_by(cyl) %.%
            mutate(
                newvar2 = newvar + mean(cyl)
            )

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