Нестандартная оценка и квазиквотация в dplyr () работает не так, как (наивно) ожидалось

Я пытаюсь выполнить поиск в базе данных, а затем пометить выход именем, полученным из исходного поиска, "derived_name" в воспроизводимом примере ниже. Я использую dplyr pipe %>%, и у меня возникают проблемы с квазиквотированием и / или нестандартной оценкой. В частности, при использовании count_colname, символьного объекта, производного от "derived_name", в последней функции top_n() не удается выделить подмножество фрейма данных.

search_name <- "derived_name"
set.seed(1)
letrs <- letters[rnorm(52, 13.5, 5)]
letrs_count.df <- letrs %>%
    table() %>%
    as.data.frame()
count_colname <- paste0(search_name, "_letr_count")
colnames(letrs_count.df) <- c("letr", count_colname)
letrs_top.df <- letrs_count.df %>%
    top_n(5, count_colname)
identical(letrs_top.df, letrs_count.df)
# [1] TRUE

На основе этого обсуждения Я думал, что приведенный выше код сработает. И этот пост побудил меня попробовать top_n_(), которого, похоже, не существует.

Я изучаю vignette("programming"), что немного выше моей головы. Этот пост побудил меня попробовать синтаксис !! sym(), который работает, но я понятия не имею Почему! Мы будем очень признательны за помощь в понимании того, почему работает приведенный ниже код. Спасибо.

colnames(letrs_count.df) <- c("letr", count_colname)
letrs_top.df <- letrs_count.df %>%
    top_n(5, (!! sym(count_colname)))
letrs_top.df
#   letr derived_name_letr_count
# 1    l                       5
# 2    m                       6
# 3    o                       7
# 4    p                       5
# 5    q                       6

Дополнительные сбивающие с толку примеры, основанные на приведенных ниже вопросах и комментариях @lionel и @Tung. Что меня сбивает с толку, так это то, что в справке fils сказано, что sym() «принимает строки в качестве входных данных и превращает их в символы» и !! «отменяет кавычки своего аргумента». Однако в приведенных ниже примерах sym(count_colname) отменяет кавычку на derived_name_letr_count. Я не понимаю, зачем !! нужен в !! sym(count_colname), поскольку sym(count_colname) и qq_show(!! sym(count_colname)) дают одинаковое значение.

count_colname
# [1] "derived_name_letr_count"
sym(count_colname)
# derived_name_letr_count
qq_show(count_colname)
# count_colname
qq_show(sym(count_colname))
# sym(count_colname)
qq_show(!! sym(count_colname))
# derived_name_letr_count
qq_show(!! count_colname)
# "derived_name_letr_count"

person Josh    schedule 08.08.2018    source источник
comment
dplyr автоматически цитирует свои входные данные. Вот исходный код top_n: он использует enquo & !!, чтобы цитировать и отменять цитирование входных данных. Запустите qq_show(!!quo(sym(count_colname))), чтобы узнать, почему вам нужно сначала убрать кавычки sym(count_colname) с помощью !! перед отправкой в ​​top_n   -  person Tung    schedule 12.09.2018


Ответы (2)


Согласно top_n документации (?top_n), он не поддерживает ввод _3 _ / _ 4_, поэтому 1-й пример не сработал. Во втором примере rlang::sym преобразовал строку в имя переменной, а затем !! выделил ее без кавычек, чтобы ее можно было оценить внутри top_n. Примечание. top_n и другие _ 9_ глаголы автоматически цитируют вводимые данные.

Используя rlang::qq_show, как предлагает @lionel, мы видим, что это не работает, потому что в letrs_count.df нет столбца count_colname

library(tidyverse)

set.seed(1)
letrs <- letters[rnorm(52, 13.5, 5)]
letrs_count.df <- letrs %>%
  table() %>%
  as.data.frame()

search_name <- "derived_name"
count_colname <- paste0(search_name, "_letr_count")
colnames(letrs_count.df) <- c("letr", count_colname)
letrs_count.df
#>    letr derived_name_letr_count
#> 1     b                       1
#> 2     c                       1
#> 3     f                       2
...

rlang::qq_show(top_n(letrs_count.df, 5, count_colname))
#> top_n(letrs_count.df, 5, count_colname)

sym & !! создать правильное имя столбца, существующее в letrs_count.df

rlang::qq_show(top_n(letrs_count.df, 5, !! sym(count_colname)))
#> top_n(letrs_count.df, 5, derived_name_letr_count)

letrs_count.df %>%
  top_n(5, !! sym(count_colname))
#>   letr derived_name_letr_count
#> 1    l                       5
#> 2    m                       6
#> 3    o                       7
#> 4    p                       5
#> 5    q                       6

top_n(x, n, wt)

Аргументы:

  • x: a tbl() для фильтрации

  • n: количество возвращаемых строк. Если x сгруппирован, это количество строк в группе. Будет включать более n строк, если есть связи. Если n положительно, выбираются первые n строк. Если отрицательно, выбираются нижние n строк.

  • wt: (Необязательно). Переменная, используемая для упорядочивания. Если не указано, по умолчанию используется последняя переменная в tbl. Этот аргумент автоматически цитируется и позже оценивается в контексте фрейма данных. Он поддерживает отключение цитирования. См. vignette("programming") для ознакомления с этими концепциями.

См. Также эти ответы: 1-й, 2-й, 3-й

person Tung    schedule 08.08.2018
comment
Спасибо. 3-й пост, на который вы ссылались, заставил меня подумать, что это работает x <- enquo(count_coln); laut.top.df <- laut.count.df %>% top_n(max(10, ceiling(percent * nrow(.) / 100)), !! x), но это не так. Это определенно самая разочаровывающая концепция, с которой я столкнулся. - person Josh; 08.08.2018
comment
@ Джош: что такое count_coln? enquo обычно используется внутри функции. Предлагаю вам посмотреть 5-минутное оценочное видео Хэдли - person Tung; 08.08.2018
comment
спасибо, я подумал, была ли это проблема с enquo. Все еще пытаюсь понять, что делает sym. count_colname представляет то, что я хочу, чтобы имя столбца было. Он состоит из уникального идентификатора, полученного в результате моего первоначального поиска по базе данных ("derived_name" в примере) и "_letr_count" Я делаю его здесь count_colname <- paste0(search_name, "_letr_count") и использую здесь colnames(letrs_count.df) <- c("letr", count_colname) и в функции top_n, которая вызывает у меня проблемы. - person Josh; 08.08.2018
comment
sym() преобразует строку в имя переменной. Я предлагаю вам использовать rlang::qq_show(), чтобы поэкспериментировать с отключением цитирования и посмотреть результаты. Например, попробуйте var <- "cyl"; rlang::qq_show(mutate(data, !!var + 1)). Тогда попробуйте с !!sym(var) - person Lionel Henry; 08.08.2018
comment
@Josh: Эта ссылка может помочь облегчить вашу боль при переходе к tidyeval colinfay.me/tidyeval-1 - person Tung; 08.08.2018

Итак, я понял, что то, с чем я боролся в этом вопросе (и многих других проблемах), на самом деле не квазиквотация и / или нестандартная оценка, а скорее преобразование символьных строк в имена объектов. Вот мое новое решение:

letrs_top.df <- letrs_count.df %>%
    top_n(5, get(count_colname))
person Josh    schedule 30.03.2019