如何创建一个函数来改变具有变量名和“_pct”的新列?

How do I create a function to mutate new columns with a variable name and "_pct"?

mtcars为例。我想编写一个函数来创建 countpct 列,如下所示 -

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。因此,如果我想使用 dispdisp 将是我的 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