R语言dplyr的mutate(across())如何向自定义函数传入列名
高版本dplyr下across传递列名的实现方法
核心机制
- 高版本dplyr在
across()执行环境中内置专属辅助函数cur_column(),可直接返回当前正在处理的列的字符串名称,是替代旧版mutate_at()列名获取逻辑的标准方案。 across()支持两种自定义函数的列名获取路径:- 常规命名函数:函数内部可直接调用
cur_column()获取当前列名,搭配列值完成计算 - lambda匿名函数:通过
.x获取当前列的数值向量,搭配cur_column()可显式将列名传入自定义函数
- 常规命名函数:函数内部可直接调用
现有代码的问题
- 原
si_calc入参x仅接收列的数值向量,直接传入select()会因参数类型不匹配(select()需要列名字符串)导致选列失败 - 原函数未绑定across执行上下文的列名获取逻辑,无法匹配对应年份列的计算要求
- 原函数体用圆括号包裹容易引入语法歧义,建议统一用花括号
{}包裹返回逻辑
修正后的可运行实现
- 调整自定义函数逻辑,通过
cur_column()获取当前列名:si_calc <- function(na.rm = FALSE) { current_col <- cur_column() pull( test1 %>% filter(mode == "PLDV", var == "PMT") %>% select(all_of(current_col)) / 1000 ) } - 直接在
across()中调用调整后的函数即可:test2 %>% filter(scenario == "BAU", mode == "PLDV", fuel == "SI") %>% mutate(across(yrs, si_calc))
显式传参的备选方案
如果需要让自定义函数不依赖全局执行环境,可将列名作为显式入参传递:
- 调整自定义函数结构,新增列名入参:
si_calc_v2 <- function(x, col_name, na.rm = FALSE) { pull( test1 %>% filter(mode == "PLDV", var == "PMT") %>% select(all_of(col_name)) / 1000 ) } - 在
across()中通过lambda表达式同时传入列值、列名:test2 %>% filter(scenario == "BAU", mode == "PLDV", fuel == "SI") %>% mutate(across(yrs, ~si_calc_v2(x = .x, col_name = cur_column())))
关键说明
- 取列时建议用
all_of()包裹列名字符串,避免dplyr非标准求值产生的告警 - 原代码中
pull()的使用逻辑完全合理:test1筛选后得到的列是长度为3的向量,和test2筛选后的行数完全匹配,可直接按位置批量赋值,不需要逐元素循环计算
内容的提问来源于stack exchange,提问作者Jason Hawkins
相关产品推荐
相关产品推荐

