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