如何迭代使用整洁评估的函数(通过
rlang
的 curly-curly)?
这是一个基本示例,我尝试使用
purrr::map()
迭代列名称:
library("dplyr")
library("purrr")
myfunc <- function(by) {
mtcars %>% count({{ by }})
}
# passing unquoted arguments doesn't work
c(cyl, vs, am, gear) %>% map(~ myfunc(by = .x))
#> Error in eval(expr, envir, enclos): object 'cyl' not found
# passing quoted arguments also doesn't work
c("cyl", "vs", "am", "gear") %>% map(~ myfunc(by = .x))
#> Error in `map()`:
#> ℹ In index: 1.
#> Caused by error in `count()`:
#> ! Must group by variables found in `.data`.
#> ✖ Column `.x` is not found.
创建于 2024-03-18,使用 reprex v2.1.0
如何解决这个问题?
当您尝试创建不带引号的符号向量
c(cyl, vs, am, gear)
时,R 将尝试在管道中的下一步之前对其进行评估。全局环境中不存在 cyl
、vs
、am
或 gear
,因此这将失败。
如果你想以这种方式做事,你可以明确告诉 R 这些参数直到稍后才被评估,这可以使用
rlang::quos()
: 来完成
library(dplyr)
library(purrr)
myfunc <- function(by) {
mtcars %>% count({{ by }})
}
# passing unquoted arguments doesn't work
rlang::quos(cyl, vs, am, gear) %>% map(~ myfunc(by = !!.x))
#> [[1]]
#> cyl n
#> 1 4 11
#> 2 6 7
#> 3 8 14
#>
#> [[2]]
#> vs n
#> 1 0 18
#> 2 1 14
#>
#> [[3]]
#> am n
#> 1 0 19
#> 2 1 13
#>
#> [[4]]
#> gear n
#> 1 3 15
#> 2 4 12
#> 3 5 5
创建于 2024-03-18,使用 reprex v2.1.0
请注意,您还需要使用
!!
才能正常工作 - 否则 R 将查找名为 .x
的列。
更惯用的方法是使用字符向量并对
.data
代词进行子集化,如下所示:
c("cyl", "vs", "am", "gear") %>%
map(~ myfunc(by = .data[[.x]]))
您还可以将
across()
与 all_of()
结合使用:
c("cyl", "vs", "am", "gear") %>%
map(~ myfunc(by = across(all_of(.x))))
如您所见,您可以采取多种方法 - 这是一个广泛的主题。要了解更多信息,我建议阅读
vignette("programming", package = "dplyr")
。
这是解决此问题的一种替代方法:
c("cyl", "vs", "am", "gear") %>% map(~ myfunc(by = !!sym(.)))
[[1]]
cyl n
1 4 11
2 6 7
3 8 14
[[2]]
vs n
1 0 18
2 1 14
[[3]]
am n
1 0 19
2 1 13
[[4]]
gear n
1 3 15
2 4 12
3 5 5