R rlang: использовать .x в map () вместе с quosure? - PullRequest
4 голосов
/ 07 мая 2019

Я пытаюсь передать набор переменных / значений в data.frame в функцию map, но не уверен, как справиться с тем фактом, что .x относится к предложению, которое необходимо оценить:mutate(df2 = map2(variable, value, ~filter(df1, .x==.y))) Наивный !!.x не будет работать.

Здесь мой data.frame имеет один столбец для переменной , один для значения , который будет отображен ввызов фильтра:

tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) 
#> # A tibble: 2 x 2
#>   variable value
#>   <chr>    <chr>
#> 1 wool     A    
#> 2 tension  L

Как я могу передать их в фильтр?Должен ли я объявить вместо переменная как quosure?Я попробовал несколько подходов:

library(tidyverse)
data(warpbreaks)

tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) %>% 
  mutate(data_filtered=map2(variable, value, ~filter(warpbreaks, .x==.y)))
#> # A tibble: 2 x 3
#>   variable value data_filtered       
#>   <chr>    <chr> <list>              
#> 1 wool     A     <data.frame [0 × 3]>
#> 2 tension  L     <data.frame [0 × 3]>

tibble(variable=c(quo(wool), quo(tension)), 
       value= c("A", "L")) %>% 
  mutate(data_filtered=map2(variable, value, ~filter(warpbreaks, eval_tidy(.x)==.y)))
#> Error in eval_tidy(.x): object 'wool' not found

Ответы [ 3 ]

1 голос
/ 09 мая 2019

В вашем примере вы пытаетесь использовать вложенные глаголы dplyr: внутри mutate() есть filter(). Это хорошо работает для обычного использования, но мы должны быть немного осторожны при использовании функций tidy eval, потому что они применяются очень рано, когда вызывается внешняя функция. По этой причине часто возникает проблема синхронизации, если вы пытаетесь использовать !! или .data во внутреннем глаголе.

@ ответ zack показывает, как можно разложить проблему в два этапа, чтобы избежать вложенной проблемы. В этом случае другая возможность - пропустить шаг mutate(), сопоставив его непосредственно с df (за идею @Spacedman). Здесь мы собираемся использовать pmap(), который отображается параллельно над списком или фреймом данных:

# For pretty-printing
options(tibble.print_max = 5, tibble.print_min = 5)
warpbreaks <- as_tibble(warpbreaks)

pmap(df, ~ filter(warpbreaks, .data[[.x]] == .y))
#> [[1]]
#> # A tibble: 27 x 3
#>   breaks wool  tension
#>    <dbl> <fct> <fct>
#> 1     26 A     L
#> 2     30 A     L
#> 3     54 A     L
#> 4     25 A     L
#> 5     70 A     L
#> # … with 22 more rows
#>
#> [[2]]
#> # A tibble: 18 x 3
#>   breaks wool  tension
#>    <dbl> <fct> <fct>
#> 1     26 A     L
#> 2     30 A     L
#> 3     54 A     L
#> 4     25 A     L
#> 5     70 A     L
#> # … with 13 more rows
1 голос
/ 09 мая 2019

Вы можете использовать собственные инструменты замещения R, rlang более полезен при работе со средами, но для более сложной замены символов (например, вложенной) база R проще (по крайней мере для меня) .

tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) %>% 
  mutate(data_filtered=map2(variable, value, ~eval(bquote(
    filter(warpbreaks, .(sym(.x)) ==.y)))))

tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) %>% 
  mutate(data_filtered=map2(variable, value, ~eval(substitute(
    filter(warpbreaks, X ==.y), list(X = sym(.x))))))

# output for either
# # A tibble: 2 x 3
#       variable value data_filtered        
#          <chr>    <chr> <list>               
#   1 wool     A     <data.frame [27 x 3]>
#   2 tension  L     <data.frame [18 x 3]>
1 голос
/ 07 мая 2019

Что-то странное происходит с оценкой анонимной функции .x.Если честно, я не уверен, что, но определение функции вне вызова map2, кажется, работает нормально (кредит @Lionel Henry за бит ~ filter(df1, !!sym(.x) == .y):

library(tidyverse)

df <- tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) 

data(warpbreaks)

# doesn't work with anonymous function
tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) %>% 
  mutate(data_filtered=map2(variable, value, ~ filter(warpbreaks, !!sym(.x) == .y)))
#> Error in is_symbol(x): object '.x' not found

# works when you define function outside of map2
temp <- function(x, y, data){
  filter(data, !!sym(x) == y)
}

tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) %>% 
  mutate(data_filtered=map2(variable, value, temp, warpbreaks))
#> # A tibble: 2 x 3
#>   variable value data_filtered        
#>   <chr>    <chr> <list>               
#> 1 wool     A     <data.frame [27 x 3]>
#> 2 tension  L     <data.frame [18 x 3]>

Создано в 2019-05-07 пакетом Представления (v0.2.1)

Вы также можете сделать следующее без внешней функции:

tibble(variable=c("wool", "tension"), 
       value= c("A", "L")) %>% 
  mutate(data_filtered = map2(variable, value, ~ filter(..3, ..3[[..1]] == ..2), warpbreaks))
#> # A tibble: 2 x 3
#>   variable value data_filtered        
#>   <chr>    <chr> <list>               
#> 1 wool     A     <data.frame [27 x 3]>
#> 2 tension  L     <data.frame [18 x 3]>
...