代码之家  ›  专栏  ›  技术社区  ›  Mridul Garg

对多个dplyr过滤器条件使用tidy eval

  •  8
  • Mridul Garg  · 技术社区  · 7 年前

    我是tidy eval的新手,尝试编写泛型函数——目前我正在努力解决的一件事是为分类变量编写多个过滤条件。这就是我现在使用的-

    create_expr <- function(name, val){
       if(!is.null(val))
         val <- paste0("c('", paste0(val, collapse = "','"), "')")
       paste(name, "%in%", val)
    }
    
    my_filter <- function(df, cols, conds){
    #   Args: 
    #     df: dataframe which is to be filtered
    #     cols: list of column names which are to be filtered
    #     conds: corresponding values for each column which need to be filtered
    
    cols <- as.list(cols)
    conds <- as.list(conds)
    
    args <- mapply(create_expr, cols, conds, SIMPLIFY = F)
    
    if(!length(args))
      stop(cat("No filters provided"))
    
    df <- df %>% filter_(paste(unlist(args), collapse = " & "))
    return(df)
    }
    
    my_filter(gapminder, cols = list("continent", "country"), 
                         conds = list("Europe", c("Albania", "France")))
    

    我想知道如何使用整洁的评估实践重新编写。我找到了关于对多个参数使用quos()的材料,但正如您所见,我这里有两个不同的参数列表,需要相互映射。

    非常感谢您的帮助,谢谢!

    1 回复  |  直到 7 年前
        1
  •  14
  •   MrFlick    7 年前

    使用tidyverse,可以将该函数重写为

    library(dplyr)
    library(purrr) # for map2()
    
    my_filter <- function(df, cols, conds){     
      fp <- map2(cols, conds, function(x, y) quo((!!(as.name(x))) %in% !!y))
      filter(df, !!!fp)
    }
    
    my_filter(gapminder::gapminder, cols = list("continent", "country"), 
              conds = list("Europe", c("Albania", "France")))
    

    这是调用

    filter(gapminder, continent %in% "Europe", country %in% c("Albania", "France"))
    

    这样做的主要原因是您可以将多个参数传递给 filter() 它们隐式地与 & . 和 map2() 只相当于 mapply 有两个对象要迭代。