R tidyverse中如何在:=运算符右侧实现动态列名赋值
问题原因
- 你当前的写法有3个核心错误:
- 直接把
{{}}放在双引号中拼写列名,无法正确解析变量值,还会把传入字符串的引号带入最终列名 - 右侧逻辑中直接写
"{{type}}perPerson"这类字符串,实际是做字符串字面量的大小比较,而非读取对应列的值做计算,因此所有行返回结果都是0 - 函数内部调用了全局环境的
df,而非传入的.data参数,会导致数据传入逻辑异常
- 直接把
修正方案
你可以通过动态构造列名字符串+.data代词读取动态列的方式实现需求,修正后的代码如下:
library(tidyverse) df <- tribble( ~geo, ~type, ~a_b_avg, ~bperPerson, "a", "b", 3, 2, "a", "b", 3, 4 ) f15 <- function(.data, geo, type) { # 构造需要引用的列名字符串 per_person_col <- paste0(type, "perPerson") avg_col <- paste0(geo, "_", type, "_avg") new_col <- paste0(geo, "_", type, "_15") .data %>% mutate(!!new_col := if_else(.data[[per_person_col]] < .data[[avg_col]], 1, 0)) } # 调用测试 result <- f15(df, "a", "b")
运行后result中的a_b_15列值为1, 0,完全符合预期。
扩展说明
如果你希望支持传入不带引号的参数(即调用形式为f15(df, a, b)),可以在函数开头先将参数转为字符串:
f15 <- function(.data, geo, type) { geo <- as_name(enquo(geo)) type <- as_name(enquo(type)) # 后续逻辑和上面完全一致 per_person_col <- paste0(type, "perPerson") avg_col <- paste0(geo, "_", type, "_avg") new_col <- paste0(geo, "_", type, "_15") .data %>% mutate(!!new_col := if_else(.data[[per_person_col]] < .data[[avg_col]], 1, 0)) }
内容的提问来源于stack exchange,提问作者nicholas
相关产品推荐
相关产品推荐

