Передайте несколько вызывающих аргументов формальному аргументу в пользовательской функции dplyr без использования "..." - PullRequest
0 голосов
/ 05 ноября 2018

Чтобы сделать настраиваемую функцию гибкой для получения одного или нескольких вызывающих аргументов на формальный аргумент, я в настоящее время полагаюсь на "...":

library(dplyr)

foo <- function(data, ..., dv){
  groups <- enquos(...)
  dv <- enquo(dv)
  data %>% 
    group_by(!!!groups) %>% 
    summarise(group_mean = mean(!!dv))
}

mtcars %>% foo(am, dv = mpg)
mtcars %>% foo(vs, am, dv = mpg)

Но «...» скрывает логику функции, и ее нельзя использовать в пользовательской функции с 2 или более формальными аргументами, требующими нескольких вызывающих аргументов.

Есть ли способ написать вышеупомянутую функцию для использования формального аргумента (например, "groups") вместо "...", который может получить одно имя вектора или вектор имен векторов в качестве аргумента (ов) ? Что-то вроде:

foo <- function(data, groups, dv){
  groups <- enquos(groups)
  dv <- enquo(dv)

  data %>% 
    group_by(!!!groups) %>% 
    summarise(group_mean = mean(!!dv))
}

# Failing code
mtcars %>% foo(groups = c(vs, am), dv = mpg)

Обратите внимание, что этот код будет работать, но необходимо, чтобы пользователь не забывал использовать quos () в теле функции:

foo <- function(data, groups, dv){
  dv <- enquo(dv)

  data %>% 
    group_by(!!!groups) %>% 
    summarise(group_mean = mean(!!dv))
}

mtcars %>% foo(groups = quos(vs, am), dv = mpg)

Вместо этого я бы хотел положиться на enquos () в теле функции.

1 Ответ

0 голосов
/ 05 ноября 2018

Мы могли бы поместить ... в конце

foo <- function(data,  dv, ...){
   groups <- enquos(...)
   dv <- enquo(dv)
   data %>% 
     group_by(!!!groups) %>% 
     summarise(group_mean = mean(!!dv))
  }

Если мы хотим передать vector из 'group', тогда один из вариантов - group_by_at

foo <- function(data, groups, dv){
  dv <- enquo(dv)

  data %>% 
     group_by_at(vars(groups)) %>% 
     summarise(group_mean = mean(!!dv))
  }

mtcars %>% 
    foo(groups = c("vs", "am"), dv = mpg)
# A tibble: 4 x 3
# Groups:   vs [?]
#     vs    am group_mean
#  <dbl> <dbl>      <dbl>
#1     0     0       15.0
#2     0     1       19.8
#3     1     0       20.7
#4     1     1       28.4

Один из вариантов, если мы хотим передать выражение без кавычек с c, это преобразовать его в выражение и затем оценить его

foo <- function(data, groups, dv){

 groups <- as.list(rlang::enexpr(groups))[-1]
 dv <- enquo(dv)
   data %>% 
      group_by(!!! groups) %>% 
      summarise(group_mean = mean(!!dv))
 }

mtcars %>% 
      foo(groups = c(vs, am), dv = mpg)
# A tibble: 4 x 3
# Groups:   vs [?]
#     vs    am group_mean
#  <dbl> <dbl>      <dbl>
#1     0     0       15.0
#2     0     1       19.8
#3     1     0       20.7
#4     1     1       28.4

Или, как упоминал @Joe в комментариях, enquo также должен работать с group_by_at

foo <- function(data, groups, dv){
   dv <- enquo(dv) 
   groups <- enquos(groups) 
   data %>% 
        group_by_at(vars(!!!groups)) %>% 
        summarise(group_mean = mean(!!dv))
   } 

mtcars %>% 
     foo(groups = c(vs, am), dv = mpg)
# A tibble: 4 x 3
# Groups:   vs [?]
#     vs    am group_mean
#  <dbl> <dbl>      <dbl>
#1     0     0       15.0
#2     0     1       19.8
#3     1     0       20.7
#4     1     1       28.4
...