在函数中获取过滤器以使用整洁的评估

时间:2017-10-26 22:08:27

标签: r dplyr rlang

我正在尝试使用dplyr根据动态变量进行过滤。

我已经发现要使过滤器工作,我需要将变量名括在括号中。但是,如果我将其编程为功能,则无法正常工作。

df_ex <- data.frame(a = 1:10, b = 11:20)

param <- quo(a)

# returns df_ex with column a, only, as expected
df_ex %>%
dplyr::select(!!param)

# returns expected df
df_ex %>%
dplyr::filter((!!param)==5)

# Now for the function
testfun <- function(test_df, filt_var){
   filt_var_mod <- quo(filt_var)

   test_df %>%
    dplyr::filter((!!filt_var_mod)==5)
}

# returns empty df, not as expected
testfun(df_ex, "a")

我想学习为自己找到关于dplyr的这些问题类型的答案,所以请随时向我推荐programming vignette的相关部分

4 个答案:

答案 0 :(得分:4)

如果您的函数接受列名作为字符,则无需引用它,另一方面,您需要将其转换为符号并立即使用{{1}在filter函数中对其进行评估} UQ语法中的!!

nse

如果要键入不带引号的列名,则需要testfun <- function(test_df, filt_var){ test_df %>% dplyr::filter((!!rlang::sym(filt_var)) == 5) } testfun(df_ex, "a") # a b #1 5 15

  

采用一个引用函数参数的符号,引用提供给该参数的R代码,捕获环境中的   函数被调用(因此键入了R代码)和bundle   他们处于困境中。

enquo

答案 1 :(得分:3)

从技术上讲,你不需要rlang或tidyeval或tibbles或dplyr来解决这类问题,基础R几乎不会让你使用引号,eval,parse和其他NSE工具做什么神圣的奶牛。从下往上烤。

编辑:@thelatemail提出的更优雅的解决方案

df_ex <- data.frame(a = 1:10, b = 11:20)

testfun <- function(test_df, filt_var) {
  test_df[test_df[,filt_var] == 5,]
}    

testfun(df_ex, "a")

返回

  a  b
5 5 15

只是为了好玩,data.table选项也可以起作用:

library(data.table)

df_ex <- data.frame(a = 1:10, b = 11:20)

testfun <- function(test_df, filt_var) {
  setDT(test_df,key = filt_var)[.(5)]
}

testfun(df_ex, "a")

返回:

   a  b
1: 5 15

答案 2 :(得分:0)

在制作简单的函数时,有时可以使用范围版本动词来代替潮汐。

例如,如果您想将名称作为函数中的字符串传递,filter_at是一个选项。

以下是使用filter_at将变量视为字符串的内容。您传递要过滤的变量,然后在all_varsany_vars中提供谓词函数。通过使用单个变量进行过滤,无论您使用哪个变量都无关紧要。

filter_at(df_ex, "a", all_vars(. == 5) )

 a  b
1 5 15

filter_at可以很容易地在函数中使用。

testfun = function(test_df, filt_var){

    test_df %>%
        dplyr::filter_at(filt_var, all_vars(. == 5) )
}

testfun(df_ex, "a")

  a  b
1 5 15

答案 3 :(得分:0)

基础NSE似乎也有效:

testfun2 <- function(test_df, filt_var){
  filt_var_mod <- substitute(filt_var)
  test_df %>% 
    dplyr::filter(eval(filt_var_mod) == 5)
}

testfun2(df_ex, a)


  a  b
1 5 15