Нестандартная оценка с использованием tidyr :: expand

У меня возникли проблемы с запуском выражений нестандартной оценки (nse) с пакетом tidyr.

По сути, я хочу развернуть два столбца, которые могут быть идентичными или нет, чтобы получить фрейм данных со всеми возможными комбинациями. Проблема в том, что это будет функция, поэтому я не буду знать заранее название столбца.

Вот минимальный пример:

library(tidyr)

dummy <- data.frame(x = c("ex1", "ex2"), y = c('cat1', 'cat2')) # dataset

tidyr::expand(dummy, x, y) # using standard evaluation works
tidyr::expand_(dummy, c("x", "y"))  # using the deprecated syntax works

# The following did not work:

  tidyr::expand(dummy, one_of('x'), y) # using select syntax
  tidyr::expand(dummy, vars('x', 'y')) # mutate_at style
  tidyr::expand(dummy, .data[[cnae_agg]], .data[[cnae_agg]])  # mutate current style  
  tidyr::expand(dummy, sym('x'), sym('y')) # trying to convert to symbols
  tidyr::expand(dummy, !!!enquos('x', 'y')) 
  tidyr::expand(dummy, !!('x'), y) # unquosure just one element
  tidyr::expand(dummy, !!!c("x", "y")) # unquosure vector of strings
  tidyr::expand(dummy, !!!c(quo("x"), quo("y"))) # unquosure vector that is being quosured before

Итак, у меня два вопроса:

1) Какой правильный синтаксис следует применять с функцией расширения tidyr?

2) Я, наверное, уже несколько раз читал главу о квазиквотации Advanced R, но это мне до сих пор не ясно, почему существует несколько разных «стилей» для использования nse с tidyverse и где именно использовать каждый.

Я могу в основном бросить что угодно, чтобы выбрать / резюмировать, что это будет работать, но при использовании mutate все реагирует по-разному.

Например:

  # mutate
  mutate(dummy, new_var = .data[['x']]) # mutate basic style
  mutate(dummy, new_var = !!'x') # this just attributes 'x' to all rows


  # mutate at
  mutate_at(dummy, .vars=vars('y'), list(~'a')) # this works
  mutate_at(dummy, .vars=vars(!!'y'), list(~'a')) # this also works
  mutate_at(dummy, .vars=vars('y'), list(~`<-`(.,!!'x'))) # if we try to use unquote to create an attribution it does not work
  mutate_at(dummy, .vars=vars('y'), list(~`<-`(.,vars(!!'x')))) # even using vars, which works for variable selection, doesnt suffice

  # select 
  select(dummy, x) # this works
  select(dummy, 'x') # this works
  select_at(dummy, vars(!!'x')) # this works
  select_at(dummy, 'x') # this works
  select_at(dummy, !!'x') # this doesnt work

Это подводит меня к моему 2) вопросу.

Есть ли обновленное руководство со всеми текущими синтаксисами для стиля tidyverse с упором на различия в использовании каждого «глагола», например, в «mutate» и «select» (т.е. когда один работает, а другой нет? )?

И как узнать, нужно ли использовать стиль mutate или select nse в других пакетах tidyverse, например tidyr?


person Elijah    schedule 23.09.2019    source источник
comment
Непонятно _1 _ ‹-_ 2_ о логике здесь. Вы выбираете столбец «y», а затем назначаете ли он другой столбец? В этом случае вы можете сделать это на отдельном шаге с помощью rename или rename_at   -  person akrun    schedule 23.09.2019
comment
Я согласен с тем, что, безусловно, было бы лучше так сделать. Я просто выделяю некоторые операции, которые вы могли бы выполнять с помощью обычного метода mutate, но которые сильно сбивают с толку при использовании nse и различных вариантов. Например, сделать атрибуцию с помощью mutate легко: mutate (dummy, x = y), но сделать это с помощью mutate_at и nse кажется сложным.   -  person Elijah    schedule 23.09.2019


Ответы (2)


Нам нужно оценить (!!) symbols

tidyr::expand(dummy,  !!! syms(c('x', 'y')))
# A tibble: 4 x 2
#  x     y    
#  <fct> <fct>
#1 ex1   cat1 
#2 ex1   cat2 
#3 ex2   cat1 
#4 ex2   cat2 

Это было бы особенно полезно, когда имена столбцов хранятся в vector и нужно сделать expand

nm1 <- c('x', 'y')
tidyr::expand(dummy, !!! syms(nm1))

В некоторых других комбинациях либо !!!, либо преобразование в symbol отсутствует в векторе character

person akrun    schedule 23.09.2019
comment
Спасибо, Акрун! Это решило проблему для меня. Однако мне нужно еще кое-что прояснить. В каких случаях мне нужно сначала преобразовать строки в символы (используя терминологию sym)? Например, мне не нужно делать это с mutate, но я помню, как раньше делал что-то подобное с as.name, используя filter. - person Elijah; 23.09.2019
comment
@Elijah Если вы передаете имена столбцов в функции, вы можете просто передать имя столбца без кавычек в mutate/summarise в mutate_at, передать строки или без кавычек в vars - person akrun; 23.09.2019
comment
@Elijah Некоторые функции устарели. filter также имеют разные вкусы с filter_at, filter_all и т. Д. Если у вас есть конкретный вопрос, на него будет легче ответить, потому что существует множество способов проведения оценки. - person akrun; 23.09.2019
comment
Спасибо, Акрун. Однако мне нужно еще немного поразмышлять над ответами. У меня в голове есть три разные версии синтаксиса dplyr, начиная со старого метода lazyeval, поэтому мне пока не ясно, что я могу сделать, а что не могу, используя то, что я знаю о последнем синтаксисе. - person Elijah; 23.09.2019
comment
@Elijah Забудьте о старых версиях lazyeval и сконцентрируйтесь на quo/enquo/sym/ensym и т. Д. Те, у которых есть префикс en, используются, когда вы передаете переменные в функцию - person akrun; 23.09.2019

Обновленное руководство по nse - это аккуратное руководство по оценке. В частности, в главе 8 рассматривается его связь с dplyr, а также общие закономерности. В вашем случае существует несколько возможных шаблонов, в зависимости от того, что вы хотите показать пользователю.

Шаблон 1: просто передайте точки, чтобы развернуть, предоставляя пользователю полный контроль над лежащим в основе expand():

f <- function(...) {tidyr::expand(dummy, ...)}
f( x, y )    # End users specifies the columns via NSE

Шаблон 2. Захватывайте вводимые пользователем данные для каждой переменной и передавайте их expand() с помощью новый оператор" curly curly ":

g <- function( var1, var2 ) {tidyr::expand(dummy, {{var1}}, {{var2}})}
g( x, y )    # Once again, NSE, but the number of arguments is controlled

Шаблон 3. Разрешите пользователю указывать аргументы в виде имен переменных ИЛИ строк. Используйте rlang::ensyms для преобразования строк в имена переменных:

h <- function(...) {tidyr::expand(dummy, !!!rlang::ensyms(...))}

# The interface now works with strings or NSE
h( "x", "y" )
h( x, y )

Шаблон 3b: если вы хотите отключить поддержку NSE и обеспечить, чтобы пользователи предоставляли аргументы только в виде строк, тогда незначительная модификация вышеуказанного шаблона будет принимать только строки:

h2 <- function(...) {tidyr::expand(dummy, !!!rlang::syms(list(...)))}
h2( "x", "y" )    # Strings OK
h2( x, y )        # Error: object 'x' not found

Обратите внимание, что функциям NSE требуется квазиквотация для обработки символов, хранящихся во внешних переменных:

# Handling strings in external variables
str_name <- "x"
h( !!str_name, "y" )
h2( str_name, "y" )    # h2 doesn't support NSE; no !! needed

# Handling variable names as unevaluated expressions (NOT strings)
var_name <- quote(y)
f( x, !!var_name )
g( x, !!var_name )
h( x, !!var_name )

# Handling lists of variable names using !!! unquote-splice
# Works with functions that accept dots
arg_names <- rlang::exprs( x, y )
f( !!!arg_names )
h( !!!arg_names )
person Artem Sokolov    schedule 23.09.2019
comment
+1 за ссылку по поводу оценки устройства. Спасибо за ответ Артем. Однако я обнаружил кое-что странное. Если я попытаюсь сначала передать имя переменной в строку, например str_name <- "x", ни один из показанных вами методов не сработает. Однако, если я использую `i‹ - function (var1, var2) {tidyr :: expand (dummy, !! sym (var1), !! sym (var2))} `Это действительно работает. - person Elijah; 23.09.2019
comment
Это потому, что функция ищет столбец с именем str_name. Используйте оператор !!, чтобы указать функциям искать вместо этого имя столбца, хранящееся внутри str_name. Пожалуйста, посмотрите мою правку. - person Artem Sokolov; 23.09.2019
comment
@Elijah: На всякий случай добавил шаблон только для строк. - person Artem Sokolov; 23.09.2019
comment
Спасибо, теперь я вижу, чего мне не хватало раньше! - person Elijah; 24.09.2019