Создание новых выражений внутри функции с использованием существующих предложений (программирование на 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 () его, но это не масштабируется для большего количества выражений. Я мог бы также создать временные столбцы в фрейме данных из базовых запросов, а затем вычислить выражение напрямую, но это кажется слишком многословным. Я полагаю, что есть более простой способ сделать это


person Andy    schedule 08.02.2018    source источник


Ответы (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)
person G. Grothendieck    schedule 08.02.2018
comment
Близко, но я хотел бы иметь возможность делать произвольные выражения с учетом числителя / знаменателя вместо того, чтобы указывать выражение деления в вызове функции - person Andy; 09.02.2018
comment
Просьба уточнить. Это уже позволяет передавать числитель в виде произвольного выражения и позволяет пробному вызову в вопросе работать без ошибок. - person G. Grothendieck; 09.02.2018
comment
А, я вижу, у меня была опечатка в вопросе, которая повторилась - я думал, что ваш пример передал g1 / g2 как выражение в my_divide - person Andy; 09.02.2018
comment
Да, я использовал тот же код, что и в вопросе, и он работает. my_divide(df, g1, g2) тоже подойдет. Также аргументами могут быть произвольные выражения - person G. Grothendieck; 09.02.2018
comment
Спасибо - все еще надеюсь увидеть это с использованием синтаксиса tidy / dplyr, но хорошо знать, что это работает - person Andy; 09.02.2018
comment
Ваш код будет работать, если вы заключите !!numerator в круглые скобки. - person G. Grothendieck; 09.02.2018

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

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

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

my_divide(df, g1 , g2)
person seasmith    schedule 09.02.2018

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

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 
person akrun    schedule 09.02.2018