You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何向多列变异函数传递字符串/直接列名形式的列参数?

问题描述

我想编写一个可对用户指定列执行变异操作的函数,需要同时支持两种传参方式:

  • 以字符串形式传递列名
  • 直接传递列名(无需加引号)

目前我找到了一种处理字符串参数的可行方法,但觉得不够简洁;而尝试直接传递列名的函数无法正常运行,附上示例代码及报错信息:

data <- tibble(
  a = 1:10,
  b = 21:30,
  c = 101:110
)

# 可用但写法繁琐的字符串版本
test_strings <- function(data, ...) {
  data %>%
    mutate_at(unlist(list(...)),
              function(x){x+5})
}

test_strings(data, "a", "b")
# 输出结果:
# A tibble: 10 x 3
#      a     b     c
#   <dbl> <dbl> <int>
# 1     6    26   101
# 2     7    27   102
# 3     8    28   103
# 4     9    29   104
# 5    10    30   105
# 6    11    31   106
# 7    12    32   107
# 8    13    33   108
# 9    14    34   109
#10    15    35   110

# 无法运行的直接传列名版本
test_sym <- function(data, ...) {
  data %>%
    mutate_at(c(...),
              function(x){x+5})
}

test_sym(data, a, b)
# 报错信息:Error in check_dot_cols(.vars, .cols) : object 'b' not found
解决方案

一、优化字符串传参的写法

你不需要用unlist(list(...))绕弯子,直接用c(...)就能接收字符串参数,因为mutate_at本身支持字符向量作为列选择器,写法更简洁:

test_strings <- function(data, ...) {
  data %>%
    mutate_at(c(...), ~ .x + 5)
}

test_strings(data, "a", "b") # 正常运行,结果和之前一致

二、让直接传列名生效的写法

直接传列名报错是因为函数会把a、b当作全局环境中的对象查找,而不是数据框里的列名。用dplyr的tidyeval语法就能解决这个问题:

方法1:用across配合c(...)(推荐,dplyr 1.0.0+版本)

across是mutate_at的替代方案,语法更直观,能直接解析传入的裸列名:

test_sym <- function(data, ...) {
  data %>%
    mutate(across(c(...), ~ .x + 5))
}

test_sym(data, a, b) # 正常运行,列a、b都加了5

方法2:用ensyms捕获符号(兼容旧版dplyr)

如果还在使用旧版dplyr,可以用rlang::ensyms把传入的裸列名转换成符号,再传给mutate_at:

test_sym <- function(data, ...) {
  cols <- rlang::ensyms(...)
  data %>%
    mutate_at(cols, ~ .x + 5)
}

test_sym(data, a, b) # 正常运行

三、同时支持两种传参方式的通用函数

想让同一个函数既能接字符串列名,又能接裸列名?用all_of()配合across就能实现:

test_universal <- function(data, ...) {
  cols <- c(...)
  data %>%
    mutate(across(all_of(cols), ~ .x + 5))
}

# 两种传参方式都能正常工作
test_universal(data, "a", "b")
test_universal(data, a, b)

内容的提问来源于stack exchange,提问作者SiriO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 21:05:49