我正在尝试将dplyr::filter()
与NSE一起使用,但是当过滤后的变量为as.Date()
时,我无法使其正常工作。
以下功能几乎可以使用:
foo <- function(d, f, var) {
d %>%
filter_(paste0(var, ">=", f))
}
d <- data.frame(a=1:10, b=1)
foo(d, f=5, var="a")
# a b
# 1 5 1
# 2 6 1
# 3 7 1
# 4 8 1
# 5 9 1
# 6 10 1
但是如果a
是一个日期,它将不起作用:
d <- data.frame(a=seq.Date(as.Date("2019-01-01"), length.out = 7, by="day"), b=1)
foo(d, f=as.Date("2019-01-05"), var="a") # or foo(d, f="2019-01-05", var="a")
# a b
# 1 2019-01-01 1
# 2 2019-01-02 1
# 3 2019-01-03 1
# 4 2019-01-04 1
# 5 2019-01-05 1
# 6 2019-01-06 1
# 7 2019-01-07 1
我也尝试过这个:
foo2 <- function(d, f, var) {
d %>%
filter(!!var >= f)
}
#foo2(d, f=5, var="a")
#foo2(d, f="2019-01-05", var="a")
在这两种情况下都不起作用,我想知道为什么foo2
不起作用。
答案 0 :(得分:2)
请勿修改您的功能。让我们专注于代码
foo(d, f = as.Date("2019-01-05"), var = "a")
如果输入f
是Date
,则函数中的语句paste0(var, ">=", f)
将返回
"a >= 2019-01-05"
(这表示列a
大于等于字符串的 "2019-01-05"
,不是日期,因为paste()
的输出始终是字符)
上面的语句没有意义,因为无法比较字符串。因此,您需要通过unclass()
或as.numeric()
将输入的日期转换为数字,例如
foo(d, f = unclass(as.Date("2019-01-05")), var = "a")
,该语句将返回 "a >= 17901"
,这是正常的逻辑语句。
输出
foo(d, f = unclass(as.Date("2019-01-05")), var = "a")
# a b
# 1 2019-01-05 1
# 2 2019-01-06 1
# 3 2019-01-07 1
请注意,“ a> = 17901” 将成功,因为可以将Dates(列a
)与数字(17910
)进行比较。
答案 1 :(得分:1)
您不需要!!
(rlang::
)。将var
放入as.name
(或as.symbol
)中以制成符号,然后在eval()
内使用filter
在函数环境中评估对象:>
library(magrittr)
library(dplyr)
d <- data.frame(a=seq.Date(as.Date("2019-01-01"), length.out = 7, by="day"), b=1)
foo2 <- function(d, f, var) {
sym <- as.name(var)
d %>%
filter(eval(sym) >= f)
}
结果:
> foo2(d, f="2019-01-05", var="a")
a b
1 2019-01-05 1
2 2019-01-06 1
3 2019-01-07 1
答案 2 :(得分:1)
尝试不将var
参数作为字符串传递。在这种情况下,您需要将功能foo
更改为:
foo <- function(d, f, var) {
var <- enquo(var)
d %>%
filter(!!var >= f)
}
foo(d, f=as.Date("2019-01-05"), var=a)