Нестандартная оценка Dplyr с именем функции, переданным в виде строки

При работе с конвейером dplyr я хотел бы передать функцию mutate, используя NSE, с именем функции, передаваемым из вектора.

Пример

Дан вектор двух имен функций:

funs <- c("sum", "mean")

Я хотел бы использовать первое значение для получения суммы:

require(dplyr)
mtcars %>% 
  group_by(cyl) %>% 
  mutate_(res = funs[1](hp))

Это приводит к ошибке:

Error in as.lazy_dots(list(...)) : attempt to apply non-function

do.call

Решение на основе do.call, кажется, дает некоторые результаты для суммы:

mtcars %>% 
  group_by(cyl) %>% 
  mutate_(res = do.call(funs[1], .))

но это не удается при попытке использовать mean:

>> mtcars %>% 
+   group_by(cyl) %>% 
+   mutate_(res = do.call(funs[2], .))
Error in mean.default(mpg = c(21, 21, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4,  : 
  argument "x" is missing, with no default

Я предполагаю, что это просто не имеет смысла в том, как оно применяется здесь. Отсюда мой вопрос: как использовать nse в dplyr, поэтому функция может быть передана как строка из вектора?


person Konrad    schedule 02.12.2016    source источник


Ответы (2)


Мы можем использовать get и get для извлечения значений одной строки. Здесь это функция, поэтому она возвращает саму функцию.

mtcars %>% 
     group_by(cyl) %>% 
     mutate(res= get(funs[1])(hp))

Для передачи дополнительных аргументов

mtcars$hp[1] <- NA
mtcars %>%
      group_by(cyl) %>% 
      mutate(res= get(funs[1])(hp, na.rm = TRUE))
person akrun    schedule 02.12.2016
comment
Как всегда, это очень полезно. Спасибо; не могли бы вы добавить краткое объяснение? Кроме того, как мне передать аргументы этой функции, например na.rm = TRUE? - person Konrad; 02.12.2016
comment
@Konrad Я обновил пост. Я не видел вашу правку в вашем комментарии ранее - person akrun; 02.12.2016
comment
Просто использовал get(), чтобы обойти nse, чтобы передать имя функции в by_row, используя строку в purrr (на самом деле purrrlyr). Это недостаточно документированное решение и ОЧЕНЬ полезно! (Кто-то, например я, должен отправить push-запрос/обновление документации). - person D. Woods; 18.02.2018
comment
@D.Woods Другим вариантом будет mtcars %>% group_by(cyl) %>% mutate(res = eval(call(funs[1], hp))) - person akrun; 18.02.2018

Оба они работают с использованием mutate, а не mutate_.

mtcars %>% 
  group_by(cyl) %>% 
  mutate(res = do.call(funs[2], list(hp)))

mtcars %>% 
  group_by(cyl) %>% 
  mutate(res = match.fun(funs[2])(hp))

Также обратите внимание, что если мы используем [[2]] вместо [2], то они будут работать как с вектором символов funs, который появляется в вопросе, так и с funs <- c(sum, mean) .

person G. Grothendieck    schedule 02.12.2016