以 mtcars
为例。我想编写一个函数来创建一个 count
和 pct
列,如下所示 -
library(tidyverse)
mtcars %>%
group_by(cyl) %>%
summarise(count = n()) %>%
ungroup() %>%
mutate(cyl_pct = count/sum(count))
这会产生输出 -
# A tibble: 3 x 3
cyl count mpg_pct
<dbl> <int> <dbl>
1 4 11 0.344
2 6 7 0.219
3 8 14 0.438
但是,我想创建一个函数,我可以在其中将 group_by
列指定为任何列,而 mutate
列将命名为 groub_by
中指定的列名,和一个 _pct
。因此,如果我想使用 disp
,disp
将是我的 group_by
变量,并且该函数将改变 disp_pct
列。
答案 0 :(得分:5)
类似于 akrun 的回答,但使用 {{
而不是 !!
:
foo = function(data, col) {
data %>%
group_by({{col}}) %>%
summarize(count = n()) %>%
ungroup %>%
mutate(
"{{col}}_pct" := count / sum(count)
)
}
foo(mtcars, cyl)
# `summarise()` ungrouping output (override with `.groups` argument)
# # A tibble: 3 x 3
# cyl count cyl_pct
# <dbl> <int> <dbl>
# 1 4 11 0.344
# 2 6 7 0.219
# 3 8 14 0.438
答案 1 :(得分:4)
假设输入不加引号,用ensym
转换为符号,在!!
内求值(group_by
),同时将符号转换为字符串(as_string
)并粘贴新列名的前缀“_pct”。在 mutate
中,我们可以使用 :=
和 !!
从创建的对象('colnm')中分配列名
library(stringr)
library(dplyr)
f1 <- function(dat, grp) {
grp <- ensym(grp)
colnm <- str_c(rlang::as_string(grp), '_pct')
dat %>%
group_by(!!grp) %>%
summarise(count = n(), .groups = 'drop') %>%
mutate(!! colnm := count/sum(count))
}
-测试
f1(mtcars, cyl)
# A tibble: 3 x 3
# cyl count cyl_pct
# <dbl> <int> <dbl>
#1 4 11 0.344
#2 6 7 0.219
#3 8 14 0.438
答案 2 :(得分:2)
这可能与我亲爱的朋友@akrun 发布的没有什么不同。但是,在我的版本中,我使用了 enquo
函数而不是 ensym
但无法获得我想要的结果。我开始做一些研究并意识到两者之间存在细微差别,我想您可能有兴趣了解。根据 nse-defuse
的文档,我已经知道 ensym
和 enquo
都用于解除 user_defined 参数,但今天我发现 ensym
返回一个原始表达式,而 {{1}返回一个quosure,它实际上是一个“包含表达式和环境的包装器”。所以我们需要一个额外的步骤来访问 enquo
所做的 quosure 表达式。在这种情况下,我们将 enquo
用于我们的目的。所以这只是编写此函数的另一个版本,我认为将来阅读这篇文章的人可能会感兴趣。
get_expr