Функции программирования: NSE в DPLYR и PURRR

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

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

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

 Data <- Data %>%
  group_by(WeekBeforeRelease) %>%
  mutate(visitors_genreother_instr = map_dbl(Genre_Category, ~ mean(Visitors[Genre_Category != .x]))) %>%
  ungroup() %>%
  as.data.frame()

Что превращает эту функцию в следующую, используя NSE, как описано здесь < / а>:

Function_Other <- function(ENDOGVAR, VARNAME, GROUP_MOVIE, GROUP_TIME){

  ENDOGVAR <- enquo(ENDOGVAR)
  VARNAME <- quo_name(enquo(VARNAME))
  GROUP_MOVIE <- enquo(GROUP_MOVIE)
  GROUP_TIME <- enquo(GROUP_TIME)

  Data <<- Data %>%
    group_by(!!GROUP_TIME) %>%
    mutate(!!VARNAME := map_dbl(!!GROUP_MOVIE, ~mean(!!ENDOGVAR[!!GROUP_MOVIE != .x]))) %>%
    ungroup() %>%
    as.data.frame()
}

Однако, похоже, это плохо справляется с подмножеством скобок в вычислении среднего значения. Если я заменю !! ENDOGVAR на Visitors, все будет работать нормально и так, как задумано. Однако, как есть, возникает следующая ошибка:

Error in NextMethod("[") : object '.x' not found 

Я рад любой помощи, которая укажет мне на понимание этой проблемы.

Заранее большое спасибо!

рондо


person Rondo Bohrens    schedule 03.04.2019    source источник


Ответы (1)


Мы можем заключить !! в фигурные скобки, чтобы избежать какого-либо приоритета операций, и теперь все должно работать нормально.

library(tidyverse)
Function_Other <- function(ENDOGVAR, VARNAME, GROUP_MOVIE, GROUP_TIME){

  ENDOGVAR <- enquo(ENDOGVAR)
  VARNAME <- quo_name(enquo(VARNAME))
  GROUP_MOVIE <- enquo(GROUP_MOVIE)
  GROUP_TIME <- enquo(GROUP_TIME)

  Data %>%
    group_by(!!GROUP_TIME) %>%
    mutate(!!VARNAME := map_dbl(!!GROUP_MOVIE, ~
           mean((!!ENDOGVAR)[(!!GROUP_MOVIE) != .x]))) %>%
    ungroup() %>%
    as.data.frame()

}


Data <- mtcars
out <- Function_Other(mpg, newcol, am, gear)
head(out, 3)
#   mpg cyl disp  hp drat    wt  qsec vs am gear carb newcol
#1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4  21.05
#2 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4  21.05
#3 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1  21.05

Обновлять

С rlang 0.4.0 (проверено с dplyr 0.8.2) мы также можем использовать {{...}} для замены, цитирования и отмены цитирования. Предыдущую функцию можно записать как

Function_OtherN <- function(ENDOGVAR, VARNAME, GROUP_MOVIE, GROUP_TIME){  


  Data %>%
    group_by({{GROUP_TIME}}) %>%
    mutate({{VARNAME}} := map_dbl({{GROUP_MOVIE}}, ~
           mean({{ENDOGVAR}}[{{GROUP_MOVIE}} != .x]))) %>%
    ungroup() %>%
    as.data.frame()

}


out1 <- Function_OtherN(mpg, newcol, am, gear)

-проверка с предыдущим выводом

identical(out1, out)
[1] TRUE
person akrun    schedule 03.04.2019
comment
Акрун, ты мой герой - большое спасибо, что решил проблему (и мою ночь!). Есть идеи, почему оценка не выполняется без скобок? - person Rondo Bohrens; 03.04.2019
comment
@RondoBohrens Причиной может быть приоритет операции, поскольку происходит много действий, когда вы создаете какое-то логическое выражение, подмножество и т. Д. - person akrun; 03.04.2019
comment
решение @akrun работает отлично, но следует отметить две вещи для хороших практик программирования (которые @akrun наверняка знает, но некоторые новые читатели могут не знать): 1. Передача данных вместо использования глобальной переменной Data. 2. передача переменных без кавычек не будет работать, если они переданы из списка или привязки c (). было бы более практично передавать их как строки - в этом случае они должны быть преобразованы (аналог enquo) с помощью 'rlang :: syms () ` - person Agile Bean; 01.08.2019