如何创建一个函数来改变具有变量名和“_pct”的新列?
How do I create a function to mutate new columns with a variable name and "_pct"?
以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
列将命名为 [=17= 中指定的列名],还有一个 _pct
。因此,如果我想使用 disp
,disp
将是我的 group_by
变量,函数将改变 disp_pct
列。
假设输入未加引号,使用 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
类似于 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
这可能与我亲爱的朋友@akrun 编辑的 post 没什么不同。但是,在我的版本中,我使用了 enquo
函数而不是 ensym
。
两者之间实际上存在细微差别,我想您可能有兴趣知道:
- 根据
nse-defuse
的文档,ensym
returns 是一个原始表达式,而 enquo
returns 是一个“quosure”,实际上是一个“包装器”包含一个表达式和一个环境”。所以我们需要一个额外的步骤来访问由 enquo
. 生成的 quosure 表达式
- 在这种情况下,我们使用
get_expr
来达到我们的目的。所以这里只是编写此函数的另一个版本,我认为将来阅读此内容的人可能会对 post 感兴趣。
library(dplyr)
library(rlang)
fn <- function(data, Var) {
Var <- enquo(Var)
colnm <- paste(get_expr(Var), "pct", sep = "_")
data %>%
group_by(!!Var) %>%
summarise(count = n()) %>%
ungroup() %>%
mutate(!! colnm := count/sum(count))
}
fn(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
以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
列将命名为 [=17= 中指定的列名],还有一个 _pct
。因此,如果我想使用 disp
,disp
将是我的 group_by
变量,函数将改变 disp_pct
列。
假设输入未加引号,使用 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
类似于 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
这可能与我亲爱的朋友@akrun 编辑的 post 没什么不同。但是,在我的版本中,我使用了 enquo
函数而不是 ensym
。
两者之间实际上存在细微差别,我想您可能有兴趣知道:
- 根据
nse-defuse
的文档,ensym
returns 是一个原始表达式,而enquo
returns 是一个“quosure”,实际上是一个“包装器”包含一个表达式和一个环境”。所以我们需要一个额外的步骤来访问由enquo
. 生成的 quosure 表达式
- 在这种情况下,我们使用
get_expr
来达到我们的目的。所以这里只是编写此函数的另一个版本,我认为将来阅读此内容的人可能会对 post 感兴趣。
library(dplyr)
library(rlang)
fn <- function(data, Var) {
Var <- enquo(Var)
colnm <- paste(get_expr(Var), "pct", sep = "_")
data %>%
group_by(!!Var) %>%
summarise(count = n()) %>%
ungroup() %>%
mutate(!! colnm := count/sum(count))
}
fn(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