首页 > 解决方案 > 如何在自定义函数中使用 mutate 创建新列

问题描述

我正在尝试构建一个函数,该函数在 mutate 函数中使用 case_when 转换现有列。最终目标是能够输入表名和列名,然后将字符串附加到现有列名,以便 mutate 函数创建一个新列。谢谢!

my_function <- function(table_name, col_name) {
  table_name %>%
    mutate(paste("new_",col_name) = case_when(as.numeric(col_name) <=4 ~ -1,
                                as.numeric(col_name) > 4 & as.numeric(col_name) <= 8 ~ 0,
                                as.numeric(col_name) > 8 ~ 1))
  }

标签: rdplyr

解决方案


您正在潜入整洁评估的美妙世界,您必须在其中ensymenquo列的名称:

my_function <- function(table_name, col_name) {
    .col = ensym(col_name)
    table_name %>%
        mutate(!!paste0("new_", col_name) := case_when(as.numeric(!!.col) <=4 ~ -1,
                                                  as.numeric(!!.col) > 4 & as.numeric(!!.col) <= 8 ~ 0,
                                                  as.numeric(!!.col) > 8 ~ 1))
}

df = tibble(x=1:10)
my_function(df, "x")
# A tibble: 10 x 2
       x new_x
   <int> <dbl>
 1     1    -1
 2     2    -1
 3     3    -1
 4     4    -1
 5     5     0
 6     6     0
 7     7     0
 8     8     0
 9     9     1
10    10     1

您可以在Programming with dplyr vignette中了解有关此内容的更多信息(包括运算符!!:=) 。

我的示例使用ensym并将参数作为字符串,以坚持您的函数。但是,更常见的是使用enquo并将参数作为列名:

my_function2 <- function(table_name, col_name) {
    .col = enquo(col_name)
    table_name %>%
        mutate(!!paste0("new_", quo_name(.col)) := case_when(as.numeric(!!.col) <=4 ~ -1,
                                                       as.numeric(!!.col) > 4 & as.numeric(!!.col) <= 8 ~ 0,
                                                       as.numeric(!!.col) > 8 ~ 1))
}
my_function2(df, x) #no quotes on the x!
# A tibble: 10 x 2
       x new_x
   <int> <dbl>
 1     1    -1
 2     2    -1
 3     3    -1
 4     4    -1
 5     5     0
 6     6     0
 7     7     0
 8     8     0
 9     9     1
10    10     1

不过,您不应该构建一个接受数字并在内部使用它的函数mutate吗?这是一个例子dplyr v1.0.0

my_function3 = function(x){
    case_when(as.numeric(x) <=4 ~ -1,
              as.numeric(x) > 4 & as.numeric(x) <= 8 ~ 0,
              as.numeric(x) > 8 ~ 1)
}
df %>% mutate(across(x, my_function3, .names="new_{col}"))

推荐阅读