我正在尝试使用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的相关部分
答案 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_vars
或any_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