如何解释 dplyr 消息 `summarise()` 通过 'x' 重新分组输出(用 `.groups` 参数覆盖)?

How to interpret dplyr message `summarise()` regrouping output by 'x' (override with `.groups` argument)?

更新到 dplyr 开发版本 0.8.99.9003 后 运行 group_by 和 summarise() 时,我开始收到一条新消息(参见 post 标题)。

下面是重新创建输出的示例:

library(tidyverse)
library(hablar)
df <- read_csv("year, week, rat_house_females, rat_house_males, mouse_wild_females, mouse_wild_males 
               2018,10,1,1,1,1
               2018,10,1,1,1,1
               2018,11,2,2,2,2
               2018,11,2,2,2,2
               2019,10,3,3,3,3
               2019,10,3,3,3,3
               2019,11,4,4,4,4
               2019,11,4,4,4,4") %>% 
  convert(chr(year,week)) %>% 
  mutate(total_rodents = rowSums(select_if(., is.numeric))) %>% 
  convert(num(year,week)) %>% 
  group_by(year,week) %>% summarise(average = mean(total_rodents))

输出小标题是正确的,但出现此消息:

summarise() regrouping output by 'year' (override with .groups argument)

这应该如何解释?当我同时按年和周分组时,为什么它报告仅按 'year' 重新分组?另外,覆盖是什么意思,我为什么要这样做?

我不认为该消息表示有问题,因为它出现在整个 dplyr 小插图中: https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html

我认为这是一条新消息,因为它只出现在最近的 SO 问题上,例如 and (两者都没有解决 regrouping/override 消息)。

谢谢!

这只是一条友好的警告信息。默认情况下,如果 summarise 之前有任何分组,它会删除一个组变量,即 group_by 中指定的最后一个。如果只有一个分组变量,则summarise后不会有任何分组属性,如果有多个,即这里是两个,那么,分组的属性将减少为1,即数据将将 'year' 作为分组属性。作为一个可重现的例子

library(dplyr)
mtcars %>%
     group_by(am) %>% 
     summarise(mpg = sum(mpg))
#`summarise()` ungrouping output (override with `.groups` argument)
# A tibble: 2 x 2
#     am   mpg
#* <dbl> <dbl>
#1     0  326.
#2     1  317.

消息是它正在 ungrouping,即当有单个 group_by 时,它会在 summarise

之后删除该分组
mtcars %>% 
   group_by(am, vs) %>% 
   summarise(mpg = sum(mpg))
#`summarise()` regrouping output by 'am' (override with `.groups` argument)
# A tibble: 4 x 3
# Groups:   am [2]
#     am    vs   mpg
#  <dbl> <dbl> <dbl>
#1     0     0  181.
#2     0     1  145.
#3     1     0  118.
#4     1     1  199.

在这里,它删除最后一个分组并使用 'am'

重新分组

如果我们检查 ?summarise,则有 .groups 参数,默认情况下为 "drop_last",其他选项为 "drop""keep""rowwise"

.groups - Grouping structure of the result.

"drop_last": dropping the last level of grouping. This was the only supported option before version 1.0.0.

"drop": All levels of grouping are dropped.

"keep": Same grouping structure as .data.

"rowwise": Each row is it's own group.

When .groups is not specified, you either get "drop_last" when all the results are size 1, or "keep" if the size varies. In addition, a message informs you of that choice, unless the option "dplyr.summarise.inform" is set to FALSE.

即如果我们更改 summarise 中的 .groups,我们不会收到消息,因为组属性已被删除

mtcars %>% 
    group_by(am) %>%
    summarise(mpg = sum(mpg), .groups = 'drop')
# A tibble: 2 x 2
#     am   mpg
#* <dbl> <dbl>
#1     0  326.
#2     1  317.


mtcars %>%
   group_by(am, vs) %>%
   summarise(mpg = sum(mpg), .groups = 'drop')
# A tibble: 4 x 3
#     am    vs   mpg
#* <dbl> <dbl> <dbl>
#1     0     0  181.
#2     0     1  145.
#3     1     0  118.
#4     1     1  199.


mtcars %>% 
   group_by(am, vs) %>% 
   summarise(mpg = sum(mpg), .groups = 'drop') %>%
   str
#tibble [4 × 3] (S3: tbl_df/tbl/data.frame)
# $ am : num [1:4] 0 0 1 1
# $ vs : num [1:4] 0 1 0 1
# $ mpg: num [1:4] 181 145 118 199

以前,此警告未发出,它可能导致 OP 执行 mutate 或其他假设没有分组的情况,并导致意外输出。现在,警告给用户一个指示,我们应该小心有一个分组属性

注意:.groups 现在的生命周期是 experimental。因此,可以在未来的版本中修改该行为

根据我们是否需要基于相同的分组变量对数据进行任何转换(或不需要),我们可以 select .groups 中的不同选项。

答案在 ?summarise 中解释: “当没有指定 .groups 时,它是根据结果的行数选择的: 如果所有结果都有 1 行,您将得到“drop_last”。 如果行数不同,你会得到“保持”。

基本上,当有多个选项用作 .groups= 参数时,您会收到这样的消息。该消息警告您在计算符合上述条件的统计信息时使用了一个选项:“drop_last”或“保留”分别表示具有 1 行或多行的结果。 假设在您的管道中,由于某种原因您应用了两个或更多分组标准,但您仍然需要汇总所有跨值的数据,无论分组如何,这可以通过设置 .group = 'drop' 来完成。不幸的是,这只是理论上的,因为正如您在@akrun 的示例中看到的那样,无论在 .group = 中设置了哪个选项,统计值都保持不变(我将这些不同的选项应用于我的一个数据集并获得相同的结果和相同的数据帧结构('grouping structure is controlled by the .group= argument...')。但是,通过指定参数 .group,不会打印任何消息。

最重要的是,当使用汇总时,如果不使用分组标准,则会计算所有行的输出统计信息,因此 'results have 1 row'。当使用一个或多个分组标准时,输出统计量在每个组内计算,因此 'the number of rows varies' 取决于数据框中的组数。

解释已接受的答案,这只是一个友好的混淆警告。

summarise() has grouped output by 'xxx'

应阅读:输出 正常并且包含 所有分组列 作为属性,只有 分组键可能是有限的。

通过 cyl, am 计算 mean(mpg)

mtcars 进行分组的示例
mtcars %>% group_by(cyl, am) %>% summarise(avg_mpg = mean(mpg))
`summarise()` has grouped output by 'cyl'. You can override using the `.groups` argument.
# A tibble: 6 x 3
# Groups:   cyl [3]
    cyl    am avg_mpg
  <dbl> <dbl>   <dbl>
1     4     0    22.9
2     4     1    28.1
3     6     0    19.1
4     6     1    20.6
5     8     0    15.0
6     8     1    15.4

警告说在输出中只有第一个原始分组键使用默认 .groups = "drop_last" 保留。请参阅行 # Groups: cyl [3].

不过,属性是完整的,cylam都定义了。

这里是可用选项的快速概览,显示了函数 group_keys()

的结果
mtcars %>% group_by(cyl, am) %>% summarise(avg_mpg = mean(mpg)) %>% group_keys() 
`summarise()` has grouped output by 'cyl'. You can override using the `.groups` argument.
# A tibble: 3 x 1
    cyl
  <dbl>
1     4
2     6
3     8

mtcars %>% group_by(cyl, am) %>% summarise(avg_mpg = mean(mpg), .groups = "keep") %>% group_keys() 
# A tibble: 6 x 2
    cyl    am
  <dbl> <dbl>
1     4     0
2     4     1
3     6     0
4     6     1
5     8     0
6     8     1

mtcars %>% group_by(cyl, am) %>% summarise(avg_mpg = mean(mpg), .groups = "drop") %>% group_keys() 
# A tibble: 1 x 0

唯一可见的结果是在使用 级联 摘要时 - 下面的示例仅生成一个摘要行,因为组键被删除。

mtcars %>% group_by(cyl, am) %>% summarise(avg_mpg = mean(mpg), .groups = "drop") %>% summarise(min_avg_mpg = min(avg_mpg))
# A tibble: 1 x 1
  min_avg_mpg
        <dbl>
1   15.0

但是由于分组属性都可用,重置分组键应该没有问题 根据需要在后续 汇总 .

之前使用 group_by(cyl, am)

这可能是 summarise_all()summarise(across(everything()... 的结果,当您有 2 个或更多分组列时

> tibble(gr1=c(1,1,2), gr2=c(1,1,2), val=1:3) %>% 
    group_by(gr1, gr2) %>% 
    summarise(across(everything(), mean))

#`summarise()` has grouped output by 'gr1'. 
# You can override using the #`.groups` argument.

# A tibble: 2 x 3
# Groups:   gr1 [2]
    gr1   gr2   val
  <dbl> <dbl> <dbl>
1     1     1   1.5
2     2     2   3


> tibble(gr1=c(1,1,2), gr2=c(1,1,2), val=1:3) %>% 
+     group_by(gr1, gr2) %>% 
+     summarise_all(mean)
# No warnings here

# A tibble: 2 x 3
# Groups:   gr1 [2]
    gr1   gr2   val
  <dbl> <dbl> <dbl>
1     1     1   1.5
2     2     2   3

因此,警告的意思是:尽管 everything(),某些列将在 summarise()

中被跳过(分组)

要解决此问题,请使用 summarise(avg_mpg = mean(mpg), .groups = "drop"), dplyr 实际上将结果 table 解释为分组,这就是他向您显示该警告的原因。