我正在尝试编写几个嵌入式函数,这些函数最终会过滤一个由矢量(id_type
中的filter_data()
)定义的列(id_types
中的load_data()
)。基于新的dplyr programming vignette,我正在尝试使用enquo
来运行我的代码,但是我遇到了一个我不知道如何处理的错误。
实际的代码更复杂(实际上需要不同的函数),但这是我可以用来复制错误的最简单的代码:
library(dplyr)
library(purrr)
data <- tibble(id_a = c(1,1,2,2,3),
id_b = 991,
id_c = c(45,45,45,1,80),
units_sold = c(21,20,24,4,5))
id_types <- c("id_a", "id_b", "id_c")
load_data <- function(){
bind_rows(pmap(list(list(data),
id_types),
filter_data))
}
filter_data <- function(df, id_type) {
quo_id_type <- enquo(id_type)
filter(df, !!quo_id_type == 1)
}
load_data()
抛出以下错误:
Error in (function (x, strict = TRUE) :
the argument has already been evaluated
Called from: (function (x, strict = TRUE)
{
caller_env <- parent.frame()
if (identical(caller_env, globalenv())) {
stop("must be called in a function")
}
if (missing(x)) {
stop("argument \"x\" is missing")
}
.Call(rlang_capturearg, NULL, NULL, pairlist(caller_env,
strict), get_env())
})(id_type)
我想要的输出:我希望代码遍历所有的id_types
,过滤df
,其中id_a == 1
,id_b == 1
或id_c == 1
(原始df上的第1,2和4行),并将它们绑定在一个新的数据框中。
如何在不删除嵌套函数的情况下使用此代码?
谢谢。
我仍然不明白为什么原始代码不起作用,但我确实找到了另一种解决方案。
替换这个:
quo_id_type <- enquo(id_type)
filter(df, !!quo_id_type == 1)
有了这个:
filter_at(df, vars(id_type), all_vars(. == 1))
如果你需要filter_data
函数,你可以切换到这个,这更容易和更明显(.data
指的是你传入df
的filter
,[[
选择id_type
列,当id_type
是一个字符串):
filter_data <- function(df, id_type) {
filter(df, .data[[id_type]] == 1)
}
如果你可以完全放弃filter_data
功能,你可以选择:
filter_at(data, vars(id_types), any_vars(. == 1))
(还放弃了bind_rows
和pmap
电话)。请注意,您需要将all_vars
更改为any_vars
,因为您正在同时评估id_types
中的所有变量。
在这个例子中,传递给filter
的参数是一个字符串(即“id_a”),但即使这样也不起作用:
> filter(data, "id_a" == 1)
# A tibble: 0 x 4
# ... with 4 variables: id_a <dbl>, id_b <dbl>, id_c <dbl>,
# units_sold <dbl>
过滤条件的计算结果为FALSE
,因为字符串"id_a"
不等于整数1
,所以没有行满足条件,所以它返回一个空的tibble
。
你传递给函数的参数实际上是id_types[[1]]
,而不是“id_a”,所以这就是你的enquo()
ing。你可以通过尝试看到:
f <- function(id_type) enquo(id_type)
f(id_types[[1]])
f("id_a")
哪个回报:
<quosure: global>
~id_types[[1]]
<quosure: empty>
~"id_a"
您可以通过将filter_data
更改为此来解决此问题(并打印其他问题)(但我不建议实际执行此操作):
filter_data <- function(df, id_type) {
id_type <- id_type
quo_id_type <- enquo(id_type)
print(quo(filter(df, !!quo_id_type == 1)))
filter(df, !!quo_id_type == 1)
}