功能中的enquo()错误:已经评估了参数

问题描述 投票:1回答:2

我正在尝试编写几个嵌入式函数,这些函数最终会过滤一个由矢量(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 == 1id_b == 1id_c == 1(原始df上的第1,2和4行),并将它们绑定在一个新的数据框中。

如何在不删除嵌套函数的情况下使用此代码?

谢谢。

r dplyr purrr
2个回答
0
投票

我仍然不明白为什么原始代码不起作用,但我确实找到了另一种解决方案。

替换这个:

quo_id_type <- enquo(id_type)

filter(df, !!quo_id_type == 1)

有了这个:

filter_at(df, vars(id_type), all_vars(. == 1))

0
投票

快速解决:

如果你需要filter_data函数,你可以切换到这个,这更容易和更明显(.data指的是你传入dffilter[[选择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_rowspmap电话)。请注意,您需要将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)
}
© www.soinside.com 2019 - 2024. All rights reserved.