Фильтрация с использованием dplyr с именами столбцов и условиями в виде строк

Я пытаюсь написать простую функцию для фильтрации data.frame. Имена столбцов, и условия фильтрации хранятся в виде строк:

vars <- c("manufacturer", "engine")
cond <- c("EMBRAER", "Turbo-fan")

Результат должен быть таким же, как результат, полученный следующим образом:

library(dplyr)
library(nycflights13)

nycflights13::planes %>%
  filter(
    .data[[vars[[1]]]] == cond[[1]],
    .data[[vars[[2]]]] == cond[[2]]
  )

Как это сделать с помощью dplyr+purrr? Длина обеих строк в действительности намного больше.


person mharinga    schedule 07.10.2019    source источник
comment
В зависимости от вашего более крупного рабочего процесса, возможно, вы могли бы вместо этого создать фрейм данных условий и использовать его для выполнения полусоединения с вашими данными, чтобы вы сохраняли только строки данных, которые соответствуют строкам в вашем фрейме данных условий.   -  person camille    schedule 07.10.2019


Ответы (2)


Альтернативный способ думать об этом состоит в том, что у вас есть набор данных условий, которые вы хотите использовать для фильтрации ваших основных данных. Создайте небольшой фрейм данных с условиями и соответствующими именами переменных, а затем преобразуйте его в фрейм данных, где эти имена переменных являются именами столбцов. Затем используйте semi_join, чтобы сохранить только строки данных, которые имеют совпадающие комбинации переменных и условий во фрейме данных условий.

vars <- c("manufacturer", "engine")
cond <- c("EMBRAER", "Turbo-fan")

library(dplyr)
library(nycflights13)

cond_df <- data.frame(vars, cond) %>%
  tidyr::spread(key = vars, value = cond)

nycflights13::planes %>%
  semi_join(cond_df, by = vars)
#> # A tibble: 298 x 9
#>    tailnum  year type        manufacturer model  engines seats speed engine
#>    <chr>   <int> <chr>       <chr>        <chr>    <int> <int> <int> <chr> 
#>  1 N10156   2004 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  2 N10575   2002 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  3 N11106   2002 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  4 N11107   2002 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  5 N11109   2002 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  6 N11113   2002 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  7 N11119   2002 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  8 N11121   2003 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#>  9 N11127   2003 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#> 10 N11137   2003 Fixed wing… EMBRAER      EMB-1…       2    55    NA Turbo…
#> # … with 288 more rows
person camille    schedule 07.10.2019

1) sym — мы можем конвертировать в symbols и evaluate (!!). [[ используется в основном для извлечения list элементов. Как показал OP, как «vars», так и «cond», поскольку vectors [ достаточно для извлечения каждого элемента

nycflights13::planes %>%
   filter(
    !!rlang::sym(vars[1]) == cond[1],
     !!rlang::sym(vars[2]) == cond[2]
  )

2) parse_expr- можно создать выражение с paste или str_c из stringr, а затем проанализировать это выражение.

expr1 <- str_c(vars, str_c('"', cond, '"'), sep="==", collapse=" & ")
nycflights13::planes %>%
    filter(!! rlang::parse_expr(expr1))
# A tibble: 298 x 9
#   tailnum  year type                    manufacturer model     engines seats speed engine   
#   <chr>   <int> <chr>                   <chr>        <chr>       <int> <int> <int> <chr>    
# 1 N10156   2004 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 2 N10575   2002 Fixed wing multi engine EMBRAER      EMB-145LR       2    55    NA Turbo-fan
# 3 N11106   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 4 N11107   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 5 N11109   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 6 N11113   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 7 N11119   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 8 N11121   2003 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 9 N11127   2003 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
#10 N11137   2003 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# … with 288 more rows

3) map2/reduce — если у нас более одного столбца, то мы могли бы использовать filter_at, но здесь 'условия' другие. Итак, один из вариантов map2

library(purrr)
library(dplyr)
map2(vars, cond, ~ nycflights13::planes %>%
                       transmute(ind = !! rlang::sym(.x) == .y) %>%
                       pull(ind)) %>%
     reduce(`&`) %>%
     filter(nycflights13::planes, .)
# A tibble: 298 x 9
#   tailnum  year type                    manufacturer model     engines seats speed engine   
#   <chr>   <int> <chr>                   <chr>        <chr>       <int> <int> <int> <chr>    
# 1 N10156   2004 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 2 N10575   2002 Fixed wing multi engine EMBRAER      EMB-145LR       2    55    NA Turbo-fan
# 3 N11106   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 4 N11107   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 5 N11109   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 6 N11113   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 7 N11119   2002 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 8 N11121   2003 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# 9 N11127   2003 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
#10 N11137   2003 Fixed wing multi engine EMBRAER      EMB-145XR       2    55    NA Turbo-fan
# … with 288 more rows
person akrun    schedule 07.10.2019