Отмена цитирования внутри map2 с помощью tidyeval

Я создаю функцию, которая вычисляет количество "прогонов" или отсутствующих или полных данных - я хочу, чтобы это работало с dplyr::group_by, поэтому я написал это как метод S3 - ниже приведен упрощенный пример этого кода.

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

Ниже приведен пример вывода

  fun_run <- function(data, var) {

    UseMethod("fun_run")

  }

fun_run.default <- function(data, var) {

  var <- rlang::enquo(var)

  data_pull <- data %>% dplyr::pull(!(!var))

  # find the lengths of the number of missings in a row
  tibble::as_tibble(c(rle(is.na(data_pull))))

}

fun_run.grouped_df <- function(data, var) {

  var <- rlang::enquo(var)

  tidyr::nest(data) %>% dplyr::mutate(data = purrr::map2(.x = data, .y = !(!var), 
                                                         .f = fun_run)) %>% tidyr::unnest()

}

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

airquality %>% fun_run(Ozone)
#> # A tibble: 35 x 2
#> lengths values
#> <int>  <lgl>
#>   4    FALSE
#>   1     TRUE
#>   4    FALSE
#>   1     TRUE
#>  14    FALSE
#>   3     TRUE
#>   4    FALSE
#>   6     TRUE
#>   1    FALSE
#>   1     TRUE
#> ... with 25 more rows

# doesn't work
airquality %>% group_by(Month) %>% fun_run(Ozone)
#> Error in mutate_impl(.data, dots) : Evaluation error: object 'Ozone' not found. 

# does work
airquality %>% group_by(Month) %>% fun_run("Ozone")
#> # A tibble: 37 x 3
#> Month lengths values
#> <int>   <int>  <lgl>
#>     5       4  FALSE
#>     5       1   TRUE
#>     5       4  FALSE
#>     5       1   TRUE
#>     5      14  FALSE
#>     5       3   TRUE
#>     5       4  FALSE
#>     6       6   TRUE
#>     6       1  FALSE
#>     6       1   TRUE
#> # ... with 27 more rows

person Nick Tierney    schedule 02.08.2017    source источник


Ответы (1)


На самом деле вы не хотите использовать map2, потому что ваш второй вход (var) не изменяется вместе с первым входом (сгруппированный / вложенный data). Кроме того, в этой точке во вложенных данных скрывается столбец «Озон». В этом можно убедиться, попробовав выполнить код без какого-либо синтаксиса tidyeval:

data <- airquality %>% group_by(Month)
tidyr::nest(data) %>% dplyr::mutate(data = purrr::map2(.x = data, .y = Ozone, 
                                                       .f = fun_run)) %>% tidyr::unnest()
#>Error in mutate_impl(.data, dots) : 
#>  Evaluation error: object 'Ozone' not found.

Вместо этого вы хотите использовать стандартный map:

tidyr::nest(data) %>% dplyr::mutate(data = purrr::map(.x = data, var = Ozone, 
                                                       .f = fun_run)) %>% tidyr::unnest()

После переписывания для использования в вашей функции:

fun_run.grouped_df <- function(data, var) {

  var <- rlang::enquo(var)

  tidyr::nest(data) %>% dplyr::mutate(data = purrr::map(.x = data, var = !!var, 
                                                        .f = fun_run)) %>% tidyr::unnest()

}

Это дает результаты из вашего последнего процитированного примера.

person Nick Nimchuk    schedule 02.08.2017
comment
Ах! Это дает именно то, что я хочу. Отлично, спасибо вам большое! Я слишком глубоко задумывался о вложенных фреймах данных, я слишком усложнял. - person Nick Tierney; 03.08.2017