具有过滤功能的日期条件的非标准评估
Non standard evaluation of date condition with filter function
我正在尝试将 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
它不起作用。
您不需要 !!
(rlang::
)。将var
围成as.name
(或as.symbol
)做成一个符号,然后在filter
里面用eval()
在函数环境中求值对象:
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
尝试不以字符串形式传递 var
参数。在这种情况下,您需要将函数 foo
更改为:
foo <- function(d, f, var) {
var <- enquo(var)
d %>%
filter(!!var >= f)
}
foo(d, f=as.Date("2019-01-05"), var=a)
不要修改你的函数。让我们专注于代码
foo(d, f = as.Date("2019-01-05"), var = "a")
如果输入 f
是 Date
,函数中的语句 paste0(var, ">=", f)
将 return
"a >= 2019-01-05"
(表示a
列大于等于"2019-01-05"
, 这是一个字符串,而不是 Date 因为 paste()
的输出总是字符)
上面的说法没有意义,因为字符串是无法比较的。所以你需要通过unclass()
或as.numeric()
将输入的日期转换为数字,例如
foo(d, f = unclass(as.Date("2019-01-05")), var = "a")
并且语句会return"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" 会成功,因为日期(列 a
)可以与数字(17910
)进行比较。
我正在尝试将 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
它不起作用。
您不需要 !!
(rlang::
)。将var
围成as.name
(或as.symbol
)做成一个符号,然后在filter
里面用eval()
在函数环境中求值对象:
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
尝试不以字符串形式传递 var
参数。在这种情况下,您需要将函数 foo
更改为:
foo <- function(d, f, var) {
var <- enquo(var)
d %>%
filter(!!var >= f)
}
foo(d, f=as.Date("2019-01-05"), var=a)
不要修改你的函数。让我们专注于代码
foo(d, f = as.Date("2019-01-05"), var = "a")
如果输入 f
是 Date
,函数中的语句 paste0(var, ">=", f)
将 return
"a >= 2019-01-05"
(表示a
列大于等于"2019-01-05"
, 这是一个字符串,而不是 Date 因为 paste()
的输出总是字符)
上面的说法没有意义,因为字符串是无法比较的。所以你需要通过unclass()
或as.numeric()
将输入的日期转换为数字,例如
foo(d, f = unclass(as.Date("2019-01-05")), var = "a")
并且语句会return"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" 会成功,因为日期(列 a
)可以与数字(17910
)进行比较。