如何通过循环批量为R数据框生成指定合并变量?
批量处理R数据框变量的循环实现方案
问题背景
现有如下R数据框:
A1_Q1 <- c(1, 2, 3) A1_Q2 <- c(4, 5, 6) A1_Q3 <- c(7, 8, 9) A1_Q4 <- c(10, 11, 12) A1_Q5 <- c(13, 14, 15) A1_Q6 <- c(16, 17, 18) A2_Q1 <- c(1, 2, 3) A2_Q2 <- c(4, 5, 6) A2_Q3 <- c(7, 8, 9) A2_Q4 <- c(10, 11, 12) A2_Q5 <- c(13, 14, 15) A2_Q6 <- c(16, 17, 18) df <- data.frame(A1_Q1, A1_Q2, A1_Q3, A1_Q4, A1_Q5, A1_Q6, A2_Q1, A2_Q2, A2_Q3, A2_Q4, A2_Q5, A2_Q6)
已手动为A1系列变量生成新变量:
df <- df %>% unite("col1a", A1_Q1, A1_Q2, sep="-", remove = FALSE) %>% unite("col1b", A1_Q3, A1_Q4, sep="-", remove = FALSE) %>% unite("col1c", A1_Q5, A1_Q6, sep="-", remove = FALSE)
希望通过循环批量对A2系列执行相同操作,生成col2a、col2b、col2c,但设想的循环无法运行:
for (i in 1:2) { df <- df %>% unite("colia", Ai_Q1, Ai_Q2, sep="-", remove = FALSE) %>% unite("colib", Ai_Q3, Ai_Q4, sep="-", remove = FALSE) %>% unite("colic", Ai_Q5, Ai_Q6, sep="-", remove = FALSE) }
问题原因
你设想的循环无法直接运行,因为R不会自动识别Ai_Q1中的i为循环变量值,会把它当作字面量变量名,导致报错找不到Ai_Q1这类变量。需要用字符串拼接+tidyeval的方式动态生成变量名和新列名。
解决方案
方案1:修改for循环,使用tidyeval动态处理
用sym()将字符串转为符号变量,glue()拼接字符串生成新列名和原变量名:
library(dplyr) library(tidyr) library(glue) for (i in 1:2) { # 生成原变量名和新列名 col_a_name <- glue("col{i}a") q1_name <- glue("A{i}_Q1") q2_name <- glue("A{i}_Q2") col_b_name <- glue("col{i}b") q3_name <- glue("A{i}_Q3") q4_name <- glue("A{i}_Q4") col_c_name <- glue("col{i}c") q5_name <- glue("A{i}_Q5") q6_name <- glue("A{i}_Q6") # 动态执行unite df <- df %>% unite(!!col_a_name, !!sym(q1_name), !!sym(q2_name), sep="-", remove=FALSE) %>% unite(!!col_b_name, !!sym(q3_name), !!sym(q4_name), sep="-", remove=FALSE) %>% unite(!!col_c_name, !!sym(q5_name), !!sym(q6_name), sep="-", remove=FALSE) }
glue():用来拼接字符串,生成符合要求的变量名sym():将字符串转为R能识别的变量符号!!:强制解引用,告诉dplyr这是一个动态变量,不是字面量
方案2:用purrr批量处理,更简洁
如果不想用for循环,可以用purrr::walk批量处理每个分组:
library(dplyr) library(tidyr) library(purrr) walk(1:2, function(i) { df <<- df %>% unite(glue("col{i}a"), all_of(glue("A{i}_Q{c(1,2)}")), sep="-", remove=FALSE) %>% unite(glue("col{i}b"), all_of(glue("A{i}_Q{c(3,4)}")), sep="-", remove=FALSE) %>% unite(glue("col{i}c"), all_of(glue("A{i}_Q{c(5,6)}")), sep="-", remove=FALSE) })
all_of():用来选择字符串对应的列,适合动态列选择<<-:因为walk是函数内操作,需要用全局赋值更新df
方案3:更高效的批量处理(无需循环)
如果变量命名规则统一,也可以直接按前缀分组处理,一步生成所有新列:
library(dplyr) library(tidyr) # 先转字符避免unite时类型问题 df <- df %>% mutate(across(starts_with("A"), as.character)) %>% rowwise() %>% mutate( col1a = paste(A1_Q1, A1_Q2, sep="-"), col1b = paste(A1_Q3, A1_Q4, sep="-"), col1c = paste(A1_Q5, A1_Q6, sep="-"), col2a = paste(A2_Q1, A2_Q2, sep="-"), col2b = paste(A2_Q3, A2_Q4, sep="-"), col2c = paste(A2_Q5, A2_Q6, sep="-") ) %>% ungroup()
这种方式适合变量数量不多的场景,代码更易读。
内容的提问来源于stack exchange,提问作者hy9fesh
相关产品推荐
相关产品推荐

