dplyr:访问当前分组变量

16

使用data.table已经有一段时间了,现在想尝试一下dplyr。很有趣,但是我不知道如何访问

  • 当前的分组变量
  • 每个组返回多个值

以下示例在data.table中可以正常工作。您将如何使用dplyr编写此代码?

library(data.table)
foo <- matrix(c(1, 2, 3, 4), ncol = 2)
dt <- data.table(a = c(1, 1, 2), b = c(4, 5, 6))

# data.table (expected)
dt[, .(c = foo[, a]), by = a]
   a c
1: 1 1
2: 1 2
3: 2 3
4: 2 4

# dplyr (?)
library(dplyr)
dt %>% 
  group_by(a) %>% 
  summarize(c = foo[a])

2
使用 summarize 可能无法完成,您可以尝试使用 do - akrun
2
你的 foo[a] 缺少逗号... 无论如何,正如 akrun 所建议的那样,summarise 不是一个好选择,因为它喜欢每个组返回一行。mutate 也不是一个好选择,因为它喜欢返回 n() 即 .N,所以你需要在 dplyr 的世界里拼凑出一些东西。 - Frank
哦,谢谢。使用以下代码仍然没有成功: dt %>% group_by(a) %>% do(c = foo[, a]) 你能给我展示一个可行的代码片段吗? - Fabian Gehring
3个回答

8

您仍然可以访问组变量,但它就像一个普通的向量,每个组都有一个唯一的值,因此如果您将unique应用于它,它将起作用。同时,dplyr似乎不会自动扩展行,就像data.table一样,您需要使用tidyr包中的unnest

library(dplyr); library(tidyr)
dt %>% 
      group_by(a) %>% 
      summarize(c = list(foo[,unique(a)])) %>% 
      unnest()

# Source: local data frame [4 x 2]

#       a     c
#   <dbl> <dbl>
# 1     1     1
# 2     1     2
# 3     2     3
# 4     2     4

或者我们可以使用first来加速,因为我们已经知道每个组的组变量向量是相同的:

dt %>% 
      group_by(a) %>% 
      summarize(c = list(foo[,first(a)])) %>% 
      unnest()

# Source: local data frame [4 x 2]

#       a     c
#   <dbl> <dbl>
# 1     1     1
# 2     1     2
# 3     2     3
# 4     2     4

8
我们可以使用来自的do函数。(不使用其他包)。 do非常适用于展开行。我们只需要用把它包起来即可。
dt %>% 
     group_by(a) %>%
     do(data.frame(c = foo[, unique(.$a)]))
#      a     c
#  <dbl> <dbl>
#1     1     1
#2     1     2
#3     2     3
#4     2     4

或者我们可以根据第一次观察来进行子集而不是使用 unique 函数。

dt %>% 
    group_by(a) %>%
    do(data.frame(c = foo[, .$a[1]]))
#     a     c
#  <dbl> <dbl>
#1     1     1
#2     1     2
#3     2     3
#4     2     4

使用 dplyr >= 1.0.0(根据 @Todd West 的评论)

dt %>%
   reframe(c = foo[, cur_group()$a], .by = 'a')
  a c
1 1 1
2 1 2
3 2 3
4 2 4

这也可以不使用任何软件包来完成。
stack(lapply(split(dt$a, dt$a), function(x) foo[,unique(x)]))[2:1]
#   ind values
#1   1      1
#2   1      2
#3   2      3
#4   2      4

作为历史注释,dplyr 1.0.0版本添加了cur_group()函数来实现此功能。因此,从2020年5月开始,可以使用cur_group()$a函数。 - Todd West
@ToddWest 我会说,使用更新版本,你可以使用 dt %>% reframe(c = foo[, first(a)], .by = 'a') - akrun

0

在分组操作(map、walk、mutate)中访问分组变量,我们可以引用自动暴露在评估上下文中的.y

示例

> iris %>% group_by(Species) %>% group_walk(~{ print(.y) })

# A tibble: 1 x 1
  Species
  <fct>
1 setosa
# A tibble: 1 x 1
  Species
  <fct>
1 versicolor
# A tibble: 1 x 1
  Species
  <fct>
1 virginica

这也在https://dplyr.tidyverse.org/reference/group_map.html中有更详细的记录。

关键是一个tibble,恰好有一行和每个分组变量的列,作为.y暴露出来。

关于其他提出的解决方案:据我所知,do不再推荐使用,而使用unique的另一个解决方案则显得笨拙(因为它需要对相关数据框进行另一个引用)。


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