Как передать строки, обозначающие выражения, в глаголы dplyr 0.7?

Я хотел бы понять, как передавать строки, представляющие выражения, в dplyr, чтобы переменные, упомянутые в строке, оценивались как выражения для столбцов в кадре данных. Основная виньетка на эту тему охватывает прохождение кавычек и вообще не обсуждает строки.

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

Например, скажем, я хочу функцию, которая выполняет групповое подсчет с использованием выражений, переданных пользователем / абонентом. Как и ожидалось, следующий код не работает, так как dplyr использует нестандартную оценку для интерпретации аргументов group_by,

library(tidyverse)

group_by_and_tally <- function(data, groups) {
  data %>%
    group_by(groups) %>%
    tally()
}

my_groups <- c('2 * cyl', 'am')
mtcars %>%
  group_by_and_tally(my_groups)
#> Error in grouped_df_impl(data, unname(vars), drop): Column `groups` is unknown

В dplyr 0.5 мы будем использовать стандартную оценку, такую ​​как group_by_(.dots = groups), чтобы справиться с этой ситуацией. Теперь, когда глаголы подчеркивания устарели, как мы должны делать такие вещи в dplyr 0.7?

В особом случае выражений, которые являются просто именами столбцов, мы можем использовать решения этого вопроса, но они не работают для более сложных выражений, таких как 2 * cyl это не просто имя столбца.

3 ответа

Решение

Важно отметить, что в этом простом примере у нас есть контроль над тем, как создаются выражения. Таким образом, лучший способ передать выражения состоит в том, чтобы создавать и передавать выражения напрямую, используя quos():

library(tidyverse)
library(rlang)

group_by_and_tally <- function(data, groups) {
  data %>%
    group_by(UQS(groups)) %>%
    tally()
}

my_groups <- quos(2 * cyl, am)
mtcars %>%
  group_by_and_tally(my_groups)
#> # A tibble: 6 x 3
#> # Groups:   2 * cyl [?]
#>   `2 * cyl`    am     n
#>       <dbl> <dbl> <int>
#> 1         8     0     3
#> 2         8     1     8
#> 3        12     0     4
#> 4        12     1     3
#> 5        16     0    12
#> 6        16     1     2

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

my_groups <- c('2 * cyl', 'am')
my_groups <- my_groups %>% map(parse_quosure)
mtcars %>%
  group_by_and_tally(my_groups)
#> # A tibble: 6 x 3
#> # Groups:   2 * cyl [?]
#>   `2 * cyl`    am     n
#>       <dbl> <dbl> <int>
#> 1         8     0     3
#> 2         8     1     8
#> 3        12     0     4
#> 4        12     1     3
#> 5        16     0    12
#> 6        16     1     2

Опять же, мы должны делать это только в том случае, если мы получаем выражения из внешнего источника, который предоставляет их в виде строк, в противном случае мы должны делать предложения непосредственно в исходном коде R.

Заманчиво использовать строки, но почти всегда лучше использовать выражения. Теперь, когда у вас есть квазиквотация, вы можете легко создавать выражения гибким способом:

lhs <- "cyl"
rhs <- "disp"
expr(!!sym(lhs) * !!sym(rhs))
#> cyl * disp

vars <- c("cyl", "disp")
expr(sum(!!!syms(vars)))
#> sum(cyl, disp)

Пакет friendlyeval может помочь вам в этом:

library(tidyverse)
library(friendlyeval)

group_by_and_tally <- function(data, groups) {
  data %>%
    group_by(!!!friendlyeval::treat_strings_as_exprs(groups)) %>%
    tally()
}

my_groups <- c('2 * cyl', 'am')
mtcars %>%
  group_by_and_tally(my_groups)

# # A tibble: 6 x 3
# # Groups:   2 * cyl [?]
# `2 * cyl`    am     n
# <dbl> <dbl> <int>
# 1         8     0     3
# 2         8     1     8
# 3        12     0     4
# 4        12     1     3
# 5        16     0    12
# 6        16     1     2
Другие вопросы по тегам