代码之家  ›  专栏  ›  技术社区  ›  tws

如何使用dplyr和tidy评估以编程方式过滤数据帧?

  •  11
  • tws  · 技术社区  · 7 年前

    假设我想过滤 starwars

    library(tidyverse)
    
    # a function that allows the user to supply filters
    filter_starwars <- function(filters) {
      for (filter in filters) {
        starwars = filter_at(starwars, filter$var, all_vars(. %in% filter$values))
      }
    
      return(starwars)
    }
    
    # filter Star Wars characters that are human, and from either Tatooine or Alderaan
    filter_starwars(filters = list(
      list(var = "homeworld", values = c("Tatooine", "Alderaan")),
      list(var = "species", values = "Human")
    ))
    

    但这不允许我指定高度过滤器,因为我已经硬编码了 %in% 中的操作员 .vars_predicate 属于 filter_at() > >= , < , <= == 操作员

    filter_starwars() 功能,以便用户可以提供足够通用的过滤器,以沿任何列进行过滤,并使用任何运算符?

    filter_()

    filter_(starwars, "species == 'Human' & homeworld %in% c('Tatooine', 'Alderaan') & height > 175")
    

    但这一点再次遭到反对。

    2 回复  |  直到 7 年前
        1
  •  14
  •   Weihuang Wong    7 年前

    尝试

    filter_starwars <- function(...) {
      F <- quos(...)
      filter(starwars, !!!F)
    }
    
    filter_starwars(species == 'Human', homeworld %in% c('Tatooine', 'Alderaan'), height > 175)
    # # A tibble: 7 × 13
    #                  name height  mass  hair_color skin_color eye_color birth_year
    #                 <chr>  <int> <dbl>       <chr>      <chr>     <chr>      <dbl>
    # 1         Darth Vader    202   136        none      white    yellow       41.9
    # 2           Owen Lars    178   120 brown, grey      light      blue       52.0
    # 3   Biggs Darklighter    183    84       black      light     brown       24.0
    # 4    Anakin Skywalker    188    84       blond       fair      blue       41.9
    # 5         Cliegg Lars    183    NA       brown       fair      blue       82.0
    # 6 Bail Prestor Organa    191    NA       black        tan     brown       67.0
    # 7     Raymus Antilles    188    79       brown      light     brown         NA
    # # ... with 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
    # #   films <list>, vehicles <list>, starships <list>
    

    看见 https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html quos 捕获 ... 作为列表,不评估参数。 !!! filter() .

        2
  •  12
  •   G. Grothendieck    7 年前

    1) 对于这个特殊的问题,我们实际上不需要 filter_ 、rlang或类似产品。这项工作:

    filter_starwars <- function(...) {
        filter(starwars, ...)
    }
    
    # test
    filter_starwars(species == 'Human', 
                    homeworld %in% c('Tatooine', 'Alderaan'), 
                    height > 175)
    )
    

    2)

    library(rlang)
    
    filter_starwars <- function(...) {
        filter(starwars, !!!parse_exprs(paste(..., sep = ";")))
    }
    
    # test
    filter_starwars("species == 'Human'", 
                    "homeworld %in% c('Tatooine', 'Alderaan')", 
                    "height > 175")
    

    2a)

    library(rlang)
    
    filter_starwars <- function(filters) {
        filter(starwars, !!!parse_exprs(paste(filters, collapse = ";")))
    }
    
    # test 
    filter_starwars(c("species == 'Human'", 
                      "homeworld %in% c('Tatooine', 'Alderaan')", 
                      "height > 175"))