如何在R语言中根据列值将列名粘贴到新列(优先用dplyr)
使用dplyr实现行级多列匹配后的列名合并
需求说明
当数据框中以susp开头的列值为1时,将对应列名合并到新列susp_dx中;若同一行有多个符合条件的列,用逗号分隔列名。
示例数据
practice <- data.frame(record_id = 1:5, susp_inflamm = c(1, 0, 0, 1, 0), susp_bacteria = c(1, 0, 0, 0, 0), susp_virus = c(0, 1, 0, 0, 0), susp_fungus = c(0, 0, 1, 0, 0))
错误代码分析
base R代码问题:
practice$susp_dx <- names(practice[,c(2:5)])[which(practice[,c(2:5)] == 1)]which(practice[,2:5]==1)返回的是整个子数据框中值为1的全局索引(按列优先),不是按行匹配的结果,导致返回的列名数量与行数不匹配,无法正确赋值。dplyr代码问题:
susp_practice <- practice %>% mutate(susp_dx = ifelse(where(is.double) & (starts_with("susp")) == 1), names(.), 0))starts_with是列选择器,必须配合select/pick等函数使用,不能直接作为条件判断- 未实现行级逻辑处理,无法针对每行单独筛选符合条件的列名
ifelse语法错误,括号不匹配
可行解决方案
方案1:dplyr + stringr(推荐,直观易读)
利用rowwise()实现行级操作,结合c_across()和pick()筛选目标列:
library(dplyr) library(stringr) practice <- practice %>% rowwise() %>% # 开启行级处理模式 mutate( susp_dx = str_c( # 获取所有susp开头的列名,筛选出当前行值为1的列名 names(pick(starts_with("susp")))[c_across(starts_with("susp")) == 1], collapse = ", " # 用逗号分隔多个列名 ) ) %>% ungroup() # 关闭行级模式,恢复默认向量操作 # 输出结果 print(practice)
执行后结果:
record_id susp_inflamm susp_bacteria susp_virus susp_fungus susp_dx 1 1 1 1 0 0 susp_inflamm, susp_bacteria 2 2 0 0 1 0 susp_virus 3 3 0 0 0 1 susp_fungus 4 4 1 0 0 0 susp_inflamm 5 5 0 0 0 0
方案2:dplyr + purrr(无需行级模式,效率更高)
利用pmap_chr()实现逐行处理,适合大数据量场景:
library(dplyr) library(purrr) library(stringr) practice <- practice %>% mutate( susp_dx = pmap_chr( select(., starts_with("susp")), # 传入所有susp开头的列 ~ str_c(names(c(...))[c(...) == 1], collapse = ", ") ) )
补充:base R替代方案
如果需要base R实现,可使用apply()逐行处理:
susp_cols <- grep("^susp", names(practice), value = TRUE) practice$susp_dx <- apply(practice[, susp_cols], 1, function(x) { paste(names(x)[x == 1], collapse = ", ") })
内容的提问来源于stack exchange,提问作者Farah
相关产品推荐
相关产品推荐

