Создание новых выражений внутри функции с использованием существующих выражений (программирование dplyr)

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

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

df <- tibble(
  g1 = c(1, 1, 2, 2, 2),
  g2 = c(1, 2, 1, 2, 1),
  a = sample(5), 
  b = sample(5)
)

my_divide <- function(df, numerator, denominator) {
  numerator <- enquo(numerator)
  denominator <- enquo(denominator)

  df %>%
    mutate(p = !!numerator / !!denominator)
}

my_divide(df, g1 , g2)

Это терпит неудачу со следующей ошибкой:

Error in !denominator : invalid argument type 

Я мог бы легко передать выражение как его собственный аргумент и enquo(), но это не масштабируется для большего количества выражений. Я также мог бы создать временные столбцы в кадре данных из базовых предложений и затем вычислить выражение напрямую, но это кажется слишком многословным. Я думаю, что есть более простой способ сделать это

3 ответа

1) / имеет более высокий приоритет, чем ! но мы хотим ! связывать более плотно, так как мы хотим!! применяется до разделения, а не после. Поставьте круглые скобки !!numerator и тогда это будет работать. Увидеть ?Syntax для документирования правил приоритета, используемых языком R.

2) Еще одна возможность, но без rlang/tidyeval это:

my_divide <- function(df, numerator, denominator = 1) {
  eval.parent(substitute(
   df %>% mutate(p = numerator / denominator)
  ))
}

my_divide(df, g1 / g2)
my_divide(df, g1, g2)

Используйте backticks для вызова функции деления.

my_divide <- function(df, numerator, denominator) {
  n <- enquo(numerator)
  d <- enquo(denominator)

  df %>%
    mutate(p = `/`(!!n, !!d))
}

my_divide(df, g1 , g2)

Можно было бы передать его как выражение в кавычках для последующей оценки

my_divide <- function(df, exprs) {  

 df %>%
    mutate(p = !! exprs) 
 }

my_divide(df, quote(g1/ g2))
# A tibble: 5 x 5
#    g1    g2     a     b     p
#  <dbl> <dbl> <int> <int> <dbl>
#1  1.00  1.00     5     2 1.00 
#2  1.00  2.00     2     4 0.500
#3  2.00  1.00     3     1 2.00 
#4  2.00  2.00     4     5 1.00 
#5  2.00  1.00     1     3 2.00 
Другие вопросы по тегам