R语言如何将var_前缀列的非零值与列名合并为新列?
R语言生成自定义res列的实现方案
问题描述
现有如下R数据框:
var_1 <- c(10, 5, 6, 0) var_2 <- c(0, 0, 3, 0) var_3 <- c(2, 0, 9, 0) df <- data.frame(var_1, var_2, var_3)
原始输出:
var_1 var_2 var_3 1 10 0 2 2 5 0 0 3 6 3 9 4 0 0 0
需要新增一列res,规则:
- 提取每行中
var_前缀列的非零值,格式为「列名(值)」,多值用逗号分隔 - 整行全为0时,
res设为NA
注:原示例第三行res仅显示var_2 (3)疑似笔误,按规则应包含所有非零值,最终期望结果如下:
var_1 var_2 var_3 res 1 10 0 2 var_1 (10), var_3 (2) 2 5 0 0 var_1 (5) 3 6 3 9 var_1 (6), var_2 (3), var_3 (9) 4 0 0 0 <NA>
实现方法
方法1:使用tidyverse工具链
借助dplyr的逐行处理能力,结合stringr格式化字符串:
library(tidyverse) df <- df %>% rowwise() %>% mutate( # 筛选非零值,生成「列名(值)」格式的字符串列表 res = list(str_c( names(.)[c_across(starts_with("var_")) != 0], " (", c_across(starts_with("var_"))[c_across(starts_with("var_")) != 0], ")", sep = "" )), # 空列表转为NA,否则合并为逗号分隔的字符串 res = case_when( length(unlist(res)) == 0 ~ NA_character_, TRUE ~ str_c(unlist(res), collapse = ", ") ) ) %>% ungroup()
方法2:基础R实现
无需额外包,用apply逐行处理:
# 定义行处理函数 format_res <- function(row_data) { non_zero_pos <- row_data != 0 if (all(!non_zero_pos)) return(NA_character_) # 生成每个非零值的格式化字符串 formatted_strs <- paste0( names(row_data)[non_zero_pos], " (", row_data[non_zero_pos], ")" ) # 合并为单个字符串 paste(formatted_strs, collapse = ", ") } # 应用到所有行 df$res <- apply(df[, startsWith(names(df), "var_")], 1, format_res)
两种方法都能生成符合要求的res列,可根据自身包依赖习惯选择。
内容的提问来源于stack exchange,提问作者JontroPothon
相关产品推荐
相关产品推荐

