group_by с нескалярными векторами символов с использованием tidyeval

Используя R 3.2.2 и dplyr 0.7.2, я пытаюсь понять, как эффективно использовать group_by с полями, предоставленными как векторы символов.

Выбор прост, я могу выбрать поле с помощью строки, подобной этой

(function(field) { 
  mpg %>% dplyr::select(field) 
})("cyl")

Несколько полей через несколько строк, как это

(function(...) { 
  mpg %>% dplyr::select(!!!quos(...)) 
})("cyl", "hwy")

и несколько полей через один вектор символов с длиной> 1, как это

(function(fields) {  
  mpg %>% dplyr::select(fields)  
})(c("cyl", "hwy"))

С group_by я действительно не могу найти способ сделать это для более чем одной строки, потому что, если мне удается получить вывод, он группируется по строке, которую я предоставляю.

Мне удалось сгруппировать по одной строке вот так

(function(field) {  
  mpg %>% group_by(!!field := .data[[field]]) %>% tally() 
})("cyl")

Что уже довольно некрасиво.

Кто-нибудь знает, что мне нужно написать, чтобы я мог бежать

(function(field) {...})("cyl", "hwy")

а также

(function(field) {...})(c("cyl", "hwy"))

соответственно? Я пробовал всевозможные комбинации !!, !!!, UQ, enquo, quos, unlist и т.д ... и сохранял их в промежуточных переменных, потому что иногда кажется, что это имеет значение, но не может заставить его работать.


person Robin Gertenbach    schedule 26.07.2017    source источник


Ответы (1)


select() в dplyr очень особенный. Он принимает не столбцы, а имена или позиции столбцов. Это единственный главный глагол, который принимает строки. (Технически, когда вы предоставляете для выбора простое имя, например cyl, оно фактически оценивается как собственное имя, а не как вектор внутри фрейма данных.)

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

myselect <- function(...) {
  syms <- syms(list(...))
  select(mtcars, !!! syms)
}
mygroup <- function(...) {
  syms <- syms(list(...))
  group_by(mtcars, !!! syms)
}

myselect("cyl", "disp")
mygroup("cyl", "disp")

Чтобы отладить отмену цитирования, оберните expr() и убедитесь, что выражение выглядит правильно:

syms <- syms(list("cyl", "disp"))
expr(group_by(mtcars, !!! syms))
#> group_by(mtcars, cyl, disp)    # yup, looks right!

См. Этот доклад, чтобы узнать больше об этом (мы обновим виньетку по программированию, чтобы сделать концепции более понятными): https://schd.ws/hosted_files/user2017/43/tidyeval-user.pdf.

Наконец, обратите внимание, что у многих глаголов есть вариант суффикса _at, который без проблем принимает строки и символьные векторы:

group_by_at(mtcars, c("cyl", "disp"))
person Lionel Henry    schedule 26.07.2017
comment
В моем личном проекте я обнаружил, что могу использовать список имен в select, но не group_by. Этот ответ помог мне понять, почему это так и как это исправить! - person Marian Minar; 20.05.2019