3

如何使用户定义的函数与管道和 group_by 很好地配合使用?这是一个简单的函数:

 library(tidyverse)

 fun_head <- function(df, column) {
 column <- enquo(column)
 df %>% select(!!column) %>% head(1)
 }

该函数与管道很好地配合使用,并允许按另一列过滤:

 mtcars %>% filter(cyl == 4) %>% fun_head(mpg)

 >    mpg
   1 22.8

但是,相同的管道工作因 group_by 而失败

mtcars %>% group_by(cyl) %>% fun_head(mpg)

Adding missing grouping variables: `cyl`
# A tibble: 1 x 2
# Groups:   cyl [1]
     cyl   mpg
     <dbl> <dbl>
1     6    21

在 group_by 之后使用“do”使其工作:

 > mtcars %>% group_by(cyl) %>% do(fun_head(., mpg))
 # A tibble: 3 x 2
 # Groups:   cyl [3]
    cyl   mpg
   <dbl> <dbl>
1     4  22.8
2     6  21  
3     8  18.7

应该如何更改函数,以便它与 filter 和 group_by 一致地工作而不需要“do”?
或者 quosures 与问题无关,而 group_by 只需要使用“do”,因为示例中的函数有多个参数?

4

2 回答 2

3

正如您编写的那样,该函数选择columnfrom df,然后采取head,这是df(head不是 tidyverse 函数,并且不知道任何分组的第一行)。dplyr::slice(1)取每组的第一行,这就是你想要的。您可以使用

 fun_head <- function(df, column) {
 column <- enquo(column)
 df %>% slice(1) %>% select(!!column)
 }

 mtcars %>% group_by(cyl) %>% fun_head(mpg)

# # A tibble: 3 x 2
# # Groups:   cyl [3]
#     cyl   mpg
#   <dbl> <dbl>
# 1     4  22.8
# 2     6  21  
# 3     8  18.7
于 2018-10-21T02:30:57.193 回答
3

这是独立于qusures的。在没有非标准评估的情况下,这是同样的问题fun_head()

fun_head <- function(df) {df %>% select(mpg) %>% head(1)}
mtcars %>% group_by( cyl ) %>% fun_head()
# Adding missing grouping variables: `cyl`
# # A tibble: 1 x 2
# # Groups:   cyl [1]
#     cyl   mpg
#   <dbl> <dbl>
# 1     6    21

正如此处此处的其他问题中所解释的,do是允许您将任意功能应用于每个组的连接器。dplyr诸如mutatefilter不要求之类的动词的原因do是因为它们在内部将分组数据帧作为特殊情况处理(例如,参见mutate 的实现)。如果您希望自己的函数模拟此行为,则需要区分分组数据帧和未分组数据帧:

fun_head2 <- function( df )
{
  if( !is.null(groups(df)) )
    df %>% do( fun_head2(.) )
  else
    df %>% select(mpg) %>% head(1)
}

mtcars %>% group_by(cyl) %>% fun_head2()
# # A tibble: 3 x 2
# # Groups:   cyl [3]
#     cyl   mpg
#   <dbl> <dbl>
# 1     4  22.8
# 2     6  21  
# 3     8  18.7

编辑:我想指出 + 的另一种替代方法group_bydo使用tidyr::nest+purrr::map代替。回到你原来的函数定义,它有两个参数:

fhead <- function(.df, .var) { .df %>% select(!!ensym(.var)) %>% head(1) }

以下两个链是等价的(最多为行排序,因为group_by按分组变量排序而nest不是):

# Option 1: group_by + do
mtcars %>% group_by(cyl) %>% do( fhead(., mpg) ) %>% ungroup

# Option 2: nest + map
mtcars %>% nest(-cyl) %>% mutate_at( "data", map, fhead, "mpg" ) %>% unnest
于 2018-10-21T02:36:10.750 回答