非标准评估非常方便 使用dplyr的动词。但使用它们可能会有问题 带有函数参数的动词。 例如,让我们说我想创建一个函数 给出了给定物种的行数。
# Load packages and prepare data
library(dplyr)
library(lazyeval)
# I prefer lowercase column names
names(iris) <- tolower(names(iris))
# Number of rows for all species
nrow(iris)
# [1] 150
此功能无法正常工作,因为species
在虹膜数据帧的上下文中进行解释
而不是在上下文中解释
函数参数:
nrowspecies0 <- function(dtf, species){
dtf %>%
filter(species == species) %>%
nrow()
}
nrowspecies0(iris, species = "versicolor")
# [1] 150
要解决非标准评估, 我通常用下划线附加参数:
nrowspecies1 <- function(dtf, species_){
dtf %>%
filter(species == species_) %>%
nrow()
}
nrowspecies1(iris, species_ = "versicolor")
# [1] 50
# Because of function name completion the argument
# species works too
nrowspecies1(iris, species = "versicolor")
# [1] 50
这并不完全令人满意 因为它将函数参数的名称更改为 不太方便用户的东西。或者它依赖于自动完成 我担心这不是编程的好习惯。 为了保持一个好的参数名称, 我能做到:
nrowspecies2 <- function(dtf, species){
species_ <- species
dtf %>%
filter(species == species_) %>%
nrow()
}
nrowspecies2(iris, species = "versicolor")
# [1] 50
解决非标准评估的另一种方法
基于this answer。
interp()
在语境中解释species
功能环境:
nrowspecies3 <- function(dtf, species){
dtf %>%
filter_(interp(~species == with_species,
with_species = species)) %>%
nrow()
}
nrowspecies3(iris, species = "versicolor")
# [1] 50
考虑到上面的3个功能, 什么是首选 - 最强大 - 实现此过滤功能的方法? 还有其他方法吗?
答案 0 :(得分:5)
@eddi 的答案对于此处发生的事情是正确的。
我正在编写另一个答案,解决了如何使用dplyr
动词编写函数的更大请求。您会注意到,最终,它使用类似nrowspecies2
的内容来避免species == species
重言式。
要编写一个包含将与NSE 一起使用的dplyr动词的函数,请编写两个函数:
首先使用lazyeval
和编写需要引用输入的版本
dplyr
动词的SE版本。所以在这种情况下,filter_
。
nrowspecies_robust_ <- function(data, species){
species_ <- lazyeval::as.lazy(species)
condition <- ~ species == species_ # *
tmp <- dplyr::filter_(data, condition) # **
nrow(tmp)
}
nrowspecies_robust_(iris, ~versicolor)
第二次制作使用NSE的版本:
nrowspecies_robust <- function(data, species) {
species <- lazyeval::lazy(species)
nrowspecies_robust_(data, species)
}
nrowspecies_robust(iris, versicolor)
* =如果你想做一些更复杂的事情,你可能需要在这里使用lazyeval::interp
,如下面提到的提示
** =如果您需要更改输出名称,请参阅.dots
参数
对于上述内容,我遵循了some tips from Hadley
另一个优秀的资源是the dplyr vignette on NSE,其中展示了.dots
,interp
以及lazyeval
包中的其他功能
有关lazyeval see it's vignette
有关使用NSE的基本R工具的详尽讨论(其中许多lazyeval
可帮助您避免),请参阅高级R中的the chapter on NSE
答案 1 :(得分:3)
这个问题与非标准评估完全无关。让我重写你的初始功能,以明确说明:
nrowspecies4 <- function(dtf, boo){
dtf %>%
filter(boo == boo) %>%
nrow()
}
nrowspecies4(iris, boo = "versicolor")
#150
filter
内的表达式始终评估为TRUE
(几乎总是 - 请参阅下面的示例),这就是为什么它不起作用,而不是因为某些NSE魔法。
您的nrowspecies2
是可行的方式。
Fwiw,您species
中的nrowspecies0
确实被评估为列,而不是输入变量species
,您可以通过将nrowspecies0(iris, NA)
与{{进行比较来检查1}}。
答案 2 :(得分:0)
in his 2016 UseR talk(@ 38min30s),Hadley Wickham解释了referential transparency的概念。使用公式,过滤函数可以重新表述为:
nrowspecies5 <- function(dtf, formula){
dtf %>%
filter_(formula) %>%
nrow()
}
这具有更多通用的附加好处
nrowspecies5(iris, ~ species == "versicolor")
# 50
nrowspecies5(iris, ~ sepal.length > 6 & species == "virginica")
# 41
nrowspecies5(iris, ~ sepal.length > 6 & species == "setosa")
# 0