Я изучаю tidyeval
семантику от a число из источников , но я получаю результат, который яне могу объяснить.
Я использую mutate_at
и case_when
для преобразования некоторых переменных путем (1) извлечения их имен с помощью кавычек, (2) изменения их имен с использованием gsub
и (3) ссылки на данные, связанные с измененными именами.
В моем минимальном примере я создаю foo$c
как преобразование foo$b
, которое должно просто принимать значение из foo$a
.Шаги (1) и (2) кажутся простыми:
library(tidyverse)
library(rlang)
foo <- data.frame(a = 1, b = 2)
foo %>%
mutate_at(vars(c = b),
funs(case_when(
TRUE ~ gsub("b", "a", as_name(quo(.)))
)))
#> a b c
#> 1 1 2 a
foo$c
содержит правильное имя переменной, на которую мы хотим посмотреть.Я понимаю, что мне нужно преобразовать строку в symbol
, используя sym()
, а затем оценить ее.Если бы я использовал простые mutate()
, !!
и sym()
, они работают нормально:
foo %>%
mutate(c := !!sym(gsub("b", "a", as_name(quo(b)))))
#> a b c
#> 1 1 2 1
Но когда я делаю это внутри mutate_at(case_when())
, я не получаю правильный результат:
foo %>%
mutate_at(vars(c = b),
funs(case_when(
TRUE ~ !!sym(gsub("b", "a", as_name(quo(.))))
)))
#> a b c
#> 1 1 2 2
Чтобы увидеть, что происходит, я сделал простую функцию печати.Без !!
из распечатки выглядит так, как будто gsub()
и sym()
дают ожидаемые результаты:
look <- function(x) {
print(x)
print(typeof(x))
return(x)
}
foo %>%
mutate_at(vars(c = b),
funs(case_when(
TRUE ~ look(sym(look(gsub("b", "a", as_name(quo(.))))))
)))
#> [1] "a"
#> [1] "character"
#> a
#> [1] "symbol"
#> Error in mutate_impl(.data, dots): Evaluation error: object of type 'symbol' is not subsettable.
Как только я поставил !!
впереди, распечатка, кажется, показывает, что мывы получаете другой результат для gsub()
и sym()
:
foo %>%
mutate_at(vars(c = b),
funs(case_when(
TRUE ~ !!(look(sym(look(gsub("b", "a", as_name(quo(.)))))))
)))
#> [1] "."
#> [1] "character"
#> .
#> [1] "symbol"
#> [1] "."
#> [1] "character"
#> .
#> [1] "symbol"
#> a b c
#> 1 1 2 2
Я не понимаю, как добавление !!
может изменить результат по сравнению с вложенным sym(gsub())
.Добавление новой операции в конец не должно изменить предыдущий / внутренний результат.Я читал, что !!
- это «не вызов функции, а синтаксическая операция», но я не совсем понимаю это различие или то, как это может изменить результат.
Использование eval_tidy
вместо !!
, кажется, работает нормально, хотя я не могу объяснить, почему:
foo %>%
mutate_at(vars(c = b),
funs(case_when(
TRUE ~ eval_tidy(look(sym(look(gsub("b", "a", as_name(quo(.)))))))
)))
#> [1] "a"
#> [1] "character"
#> a
#> [1] "symbol"
#> a b c
#> 1 1 2 1