использование квазиквотации с оператором `$`

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

Вот игрушечный пример-

library(tidyverse)

# proper implementation
tryfn <- function(data, x, y) {
  # creating a dataframe
  data <-
    dplyr::select(
      .data = data,
      !!rlang::enquo(x),
      !!rlang::enquo(y)
    ) %>% # dropping unused levels
    dplyr::mutate(.data = ., 
                  !!rlang::enquo(x) := droplevels(as.factor(!!rlang::enquo(x))))

  # checking if data is getting imported properly
  print(data)

  # figuring out number of levels in the grouping factor
  return(length(levels(data$`!!rlang::enquo(x)`))[[1]])
}

# using the function
tryfn(ggplot2::msleep, vore, brainwt)

#> # A tibble: 83 x 2
#>    vore   brainwt
#>    <fct>    <dbl>
#>  1 carni NA      
#>  2 omni   0.0155 
#>  3 herbi NA      
#>  4 omni   0.00029
#>  5 herbi  0.423  
#>  6 herbi NA      
#>  7 carni NA      
#>  8 <NA>  NA      
#>  9 carni  0.07   
#> 10 herbi  0.0982 
#> # ... with 73 more rows

#> Warning: Unknown or uninitialised column: '!!rlang::enquo(x)'.
#> [1] 0

Как видно здесь, данные импортируются правильно, но значение return неверно, потому что я не знаю, как использовать квазиквотацию в контексте оператора $. Как я могу это сделать?


person Indrajeet Patil    schedule 30.06.2019    source источник
comment
Вместо $ преобразуйте 'x' в символ с as_name и передайте его [[   -  person akrun    schedule 30.06.2019


Ответы (2)


Мы можем преобразовать в класс character с помощью as_name и извлечь с помощью [[. Чтобы избежать повторения преобразования с enquo, сделайте это один раз, сохраните идентификатор и повторно используйте

tryfn <- function(data, x, y) {
 x <- rlang::enquo(x)
 y <- rlang::enquo(y)
  # creating a dataframe
  data <-
    dplyr::select(
      .data = data,
      !!x,
      !!y
    ) %>% # dropping unused levels
    dplyr::mutate(.data = ., 
                  !!x := droplevels(as.factor(!!x)))

  # checking if data is getting imported properly
  print(data)

  # figuring out number of levels in the grouping factor
  return(length(levels(data[[rlang::as_name(x)]]))[[1]])

}

-тестирование

tryfn(ggplot2::msleep, vore, brainwt)
# A tibble: 83 x 2
#   vore   brainwt
#   <fct>    <dbl>
# 1 carni NA      
# 2 omni   0.0155 
# 3 herbi NA      
# 4 omni   0.00029
# 5 herbi  0.423  
# 6 herbi NA      
# 7 carni NA      
# 8 <NA>  NA      
# 9 carni  0.07   
#10 herbi  0.0982 
# … with 73 more rows
#[1] 4
person akrun    schedule 30.06.2019

Вы можете использовать dplyr::pull для извлечения столбца, используя семантику, аналогичную select. Используя {{...}} из rlang 0.4 для интерполяции (enquo и !! в одном) и немного упрощая,

library(tidyverse)

tryfn <- function(data, x, y) {
    data <- data %>% transmute({{x}} := as.factor({{x}}), {{y}})

    print(data)

    data %>% pull({{x}}) %>% nlevels()
}

tryfn(ggplot2::msleep, vore, brainwt)
#> # A tibble: 83 x 2
#>    vore   brainwt
#>    <fct>    <dbl>
#>  1 carni NA      
#>  2 omni   0.0155 
#>  3 herbi NA      
#>  4 omni   0.00029
#>  5 herbi  0.423  
#>  6 herbi NA      
#>  7 carni NA      
#>  8 <NA>  NA      
#>  9 carni  0.07   
#> 10 herbi  0.0982 
#> # … with 73 more rows
#> [1] 4
person alistaire    schedule 30.06.2019