可变过滤条件

时间:2019-11-21 13:54:34

标签: r dplyr

我知道这个问题很可能是重复的。我试图用谷歌搜索这个问题,但是我找不到我想要的东西。

我想做的是根据用户指定的条件过滤数据集。例如:

df <- 
  data.frame(type = c("a", "a", "b", "b"), 
           value = c(1,5,7,2), stringsAsFactors = F) %>% 
  as_tibble()

cond <- ">"
val <- 2
df %>% filter(value, cond, val)

(即与df %>% filter(value>2)相同)

如果可能的话,我将可以在函数的内部和外部使用此设置。

编辑:

当我问我的问题时,我有点着急。我真正想要的是根据用户指定的条件mutate,而不是过滤。罗纳克·沙阿(Ronak Shahs)的答案解决了filter问题,我对mutate问题做了一些小的改动。我认为没有必要发布新的问题,因为这两个问题密切相关。因此,我只发布有关mutate问题的答案(也可以回答Tjebo的评论)。

4 个答案:

答案 0 :(得分:4)

另一种方法是使用match.fun来匹配要应用的函数,并使用NSE将其应用于列。

library(dplyr)
library(rlang)

apply_fun <- function(df, col, fun, val) {
   fun1 <- match.fun(fun)
   df %>% filter(fun1({{col}}, val))
}

df %>% apply_fun(value, cond, val)

#  type  value
#  <chr> <dbl>
#1 a         5
#2 b         7

df %>% apply_fun(value, cond, 1)
# A tibble: 3 x 2
#  type  value
#  <chr> <dbl>
#1 a         5
#2 b         7
#3 b         2

答案 1 :(得分:2)

一种方法是使用eval(parse(text = ...)),即

df %>% 
 filter(eval(parse(text = paste('value', cond, val))))

# A tibble: 2 x 2
#  type  value
#  <chr> <dbl>
#1 a         5
#2 b         7

答案 2 :(得分:1)

另一个选择是:

library(tidyverse)
library(rlang)

df %>% 
  filter_at("value", ~ eval(sym(cond))(.x, val))

答案 3 :(得分:0)

请查看我的修改。

df <- 
  data.frame(type = c("a", "a", "b", "b"), 
           value = c(1,5,7,2), stringsAsFactors = F) %>% 
  as_tibble() %>% 
  mutate(cond = case_when(type == "a" ~ "==", 
                          type == "b" ~ ">="),
         val1 = case_when(type == "a" ~ 1, 
                          type == "b" ~ 3),
         val2 = case_when(type == "a" ~ 6, 
                          type == "b" ~ 7),
         val3 = case_when(type == "a" ~ 9, 
                          type == "b" ~ 0)) 

基于Ronak Shahs解决方案

apply_fun <- function(df, col, fun, val, colname = "a") {
  fun1 <- match.fun(fun)
  df <- df %>% mutate(!!colname := fun1({{col}}, val))
  df[, ncol(df)]
}

可能有一个更好的最终解决方案,但这就是我想出的。

lst <- list()
for (i in 1:nrow(df)) {
  lst[[i]] <- 
    bind_cols(
    apply_fun(df[i,], df[i,]$value, df[i,]$cond, df[i,]$val1, "type1"), 
    apply_fun(df[i,], df[i,]$value, df[i,]$cond, df[i,]$val2, "type2"),
    apply_fun(df[i,], df[i,]$value, df[i,]$cond, df[i,]$val3, "type3")
  )
}


df %>% bind_cols(., bind_rows(lst))
# A tibble: 4 x 9
  type  value cond   val1  val2  val3 type1 type2 type3
  <chr> <dbl> <chr> <dbl> <dbl> <dbl> <lgl> <lgl> <lgl>
1 a         1 ==        1     6     9 TRUE  FALSE FALSE
2 a         5 ==        1     6     9 FALSE FALSE FALSE
3 b         7 >=        3     7     0 TRUE  TRUE  TRUE 
4 b         2 >=        3     7     0 FALSE FALSE TRUE