如何使用tidyverse基于同类命名列批量创建条件计算新列
需求说明
需要批量生成多列新变量,取值规则如下:
- 每一个新列
malvol_{变量序号}_{波次}的取值由同波次的leftright_{波次}列控制 - 若
leftright_{波次}为left,取同序号同波次的malvol_right_{变量序号}_{波次}的值 - 若
leftright_{波次}为right,取同序号同波次的malvol_left_{变量序号}_{波次}的值
要求方案扩展性强,新增变量序号、波次时无需大量修改代码,且符合tidyverse开发规范。
示例数据
dt <- structure(list(malvol_left_1_w1 = c("1", "1", "4", "3", "4", "4", "1", "4", "4", "3", "1", "4", "4", "3", "4", "4", "5", "2", "4", "2"), malvol_left_2_w1 = c("1", "1", "4", "3", "4", "4", "1", "3", "4", "2", "2", "2", "4", "1", "5", "4", "5", "2", "4", "2"), malvol_right_1_w1 = c("1", "1", "4", "3", "4", "4", "1", "3", "4", "2", "1", "4", "4", "5", "5", "4", "2", "6", "4", "1" ), malvol_right_2_w1 = c("1", "1", "4", "3", "4", "4", "1", "3", "4", "2", "1", "2", "4", "5", "5", "4", "5", "5", "4", "5"), malvol_left_1_w2 = c("1", "1", "3", "3", "4", "4", "1", "5", "4", "4", "4", "2", "1", "4", "5", "4", "3", "2", "4", "4" ), malvol_left_2_w2 = c("1", "1", "3", "3", "4", "4", "7", "5", "4", "2", "3", "1", "1", "4", "4", "4", "3", "4", "4", "4"), malvol_right_1_w2 = c("1", "3", "3", "3", "4", "4", "1", "4", "4", "3", "2", "2", "4", "1", "4", "4", "5", "5", "4", "4"), malvol_right_2_w2 = c("1", "2", "3", "3", "4", "4", "1", "2", "4", "2", "3", "2", "4", "1", "4", "4", "5", "4", "4", "3"), leftright_w1 = c("right", "right", "left", "right", "right", "right", "left", "right", "right", "left", "left", "left", "left", "right", "left", "left", "right", "right", "right", "left"), leftright_w2 = c("right", "right", "left", "left", "right", "left", "left", "right", "right", "left", "left", "left", "left", "right", "left", "left", "right", "right", "left", "left")), class = "data.frame", row.names = c("12", "15", "69", "77", "95", "96", "112", "122", "150", "163", "184", "216", "221", "226", "240", "298", "305", "354", "370", "379" ))
规范tidyverse实现方案
无需提前创建空列,也无需使用eval(parse)这类不安全的写法,直接通过dplyr::across结合列名解析即可实现全自动化批量生成,新增变量、波次时无需修改核心逻辑:
library(tidyverse) dt_new <- dt %>% mutate( # 匹配所有malvol_left开头的列,自动遍历所有变量+波次组合 across(starts_with("malvol_left_"), function(x) { # 解析当前列的变量序号和波次 col_parts <- str_split(cur_column(), "_", simplify = T) var_seq <- col_parts[3] wave <- col_parts[4] # 获取对应的右列和标识列 right_col <- get(paste0("malvol_right_", var_seq, "_", wave)) flag_col <- get(paste0("leftright_", wave)) # 按规则取值 case_when( flag_col == "left" ~ right_col, flag_col == "right" ~ x ) }, # 自动重命名生成的新列 .names = "malvol_{str_remove(.col, 'malvol_left_')}") )
方案优势
- 完全兼容后续新增的变量序号、波次,只要列名符合
malvol_left_{n}_{w}、malvol_right_{n}_{w}、leftright_{w}的命名规则,不需要修改任何代码即可自动适配 - 无硬编码、无循环、无危险的解析执行语句,符合tidyverse最佳实践
- 生成的新列会自动附加到原数据集末尾,原有列全部保留
内容的提问来源于stack exchange,提问作者broti
相关产品推荐
相关产品推荐

