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

时间:2021-05-25 20:24:24

标签: r tidyeval

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 列将命名为 groub_by 中指定的列名,和一个 _pct。因此,如果我想使用 dispdisp 将是我的 group_by 变量,并且该函数将改变 disp_pct 列。

3 个答案:

答案 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 的文档,我已经知道 ensymenquo 都用于解除 user_defined 参数,但今天我发现 ensym 返回一个原始表达式,而 {{1}返回一个quosure,它实际上是一个“包含表达式和环境的包装器”。所以我们需要一个额外的步骤来访问 enquo 所做的 quosure 表达式。在这种情况下,我们将 enquo 用于我们的目的。所以这只是编写此函数的另一个版本,我认为将来阅读这篇文章的人可能会感兴趣。

get_expr