rlang::sym в анонимных функциях
Я недавно заметил, что rlang::sym
кажется, не работает в анонимных функциях, и я не понимаю, почему. Вот пример, это довольно неуклюжий и уродливый, но я думаю, что это иллюстрирует
require(tidyverse)
data <- tibble(x1 = letters[1:3],
x2 = letters[4:6],
val = 1:3)
get_it <- function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}
get_it("x1", "x2")
Это определяет некоторые игрушечные данные и (ужасную) функцию, которая по существу переименовывает столбцы на основе имен столбцов. Теперь я могу сделать то же самое для разных комбинаций a и b:
d <- tibble(x = c("x1", "x2"),
y = c("x2", "x1"))
d %>% mutate(tmp = map2(x, y, get_it))
Однако, если я пытаюсь сделать то же самое с анонимной функцией, это не сработает:
d %>% mutate(tmp = map2(x, y, function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}))
Это не с object 'a' not found
хотя функции точно такие же, только здесь, это анонимно. Кто-нибудь может объяснить почему?
1 ответ
Обратите внимание, что следующий код имеет rlang::sym()
внутри анонимной функции и работает как задумано:
map2(c("x1","x2"), c("x2","x1"), function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)})
Оригинальная проблема связана с оператором удаления кавычек !!
и его приоритет относительно создания анонимных функций внутри функций нестандартной оценки (NSE), таких как mutate
, Рассмотрим вложенный фрейм данных
XX <- data_frame( dfs = list(
data_frame( x = letters[1:3], y = 1:3 ),
data_frame( x = letters[4:6], y = 4:6 )) )
Если я попытаюсь выбрать первый столбец внутри каждого из внутренних кадров данных, используя
XX %>% mutate( dfs1 = map( dfs, function(df) {
i <- 1
df %>% select(!!i)} ))
Я получаю object 'i' not found
ошибка, потому что !!
отмена цитирования происходит относительно внешнего mutate
перед средой для анонимной функции (содержащей select
) создано. Если я переместить анонимную функцию за пределы mutate
map( XX$dfs, function(df) {
i <- 1
df %>% select(!!i)} )
это работает без проблем, потому что map
следует стандартным правилам оценки, и анонимная функциональная среда теперь создается перед удалением из кавычек.
Страница справки для !!
говорится, что
!! Оператор приводит кавычки своего аргумента. Это оценивается немедленно в окружающем контексте.
Это подразумевает, что когда вы пишете сложное выражение NSE, такое как select
внутри mutate
Отмена цитирования будет происходить в среде выражения в целом. Как отметил @lionel в комментариях, снятие кавычек в NSE имеет приоритет над другими вещами, такими как создание сред анонимных функций.