如何在R语言中基于预定义范围批量计算行求和并生成新列
问题描述
现有如下结构的数据集:
dataset <- structure( list( Participant.Id = 1:5, x1 = c(10L, 20L, 30L, 40L, 50L), x2 = c(15L, 25L, 35L, 45L, 55L), x3 = c(20L, 25L, NA, 45L, NA), x4 = c(25L, 30L, NA, 50L, NA), x5 = c(NA, 35L, NA, 55L, NA), x6 = c(NA, 35L, NA, NA, NA), y1 = c(10L, 20L, 30L, 40L, 50L), y2 = c(15L, 25L, 35L, 45L, 55L), y3 = c(20L, 25L, NA, 45L, NA), y4 = c(25L, 30L, NA, 50L, NA), y5 = c(NA, 35L, NA, 55L, NA), y6 = c(NA, 35L, NA, NA, NA), z1 = c(10L, 20L, 30L, 40L, 50L), z2 = c(15L, 25L, 35L, 45L, 55L), z3 = c(20L, 25L, NA, 45L, NA), z4 = c(25L, 30L, NA, 50L, NA), z5 = c(NA, 35L, NA, 55L, NA), z6 = c(NA, 35L, NA, NA, NA), mt1_oranges_vol = c(100L, 200L, 300L, 400L, 500L), mt2_oranges_vol = c(110L, 210L, 310L, 410L, 510L), mt3_oranges_vol = c(120L, 220L, NA, 420L, 520L), mt4_oranges_vol = c(130L, 230L, NA, 430L, NA), mt5_oranges_vol = c(NA, 240L, NA, NA, NA), mt6_oranges_vol = c(NA, NA, NA, NA, NA), mt1_pears_vol = c(101L, 201L, 301L, 401L, 501L), mt2_pears_vol = c(111L, 211L, 311L, 411L, 511L), mt3_pears_vol = c(121L, 221L, NA, 421L, 521L), mt4_pears_vol = c(131L, 231L, NA, 431L, NA), mt5_pears_vol = c(NA, 241L, NA, NA, NA), mt6_pears_vol = c(NA, NA, NA, NA, NA), mt1_apples_vol = c(102L, 202L, 302L, 402L, 502L), mt2_apples_vol = c(112L, 212L, 312L, 412L, 512L), mt3_apples_vol = c(122L, 222L, NA, 422L, 522L), mt4_apples_vol = c(132L, 232L, NA, 432L, NA), mt5_apples_vol = c(NA, 242L, NA, NA, NA), mt6_apples_vol = c(NA, NA, NA, NA, NA)), class = "data.frame", row.names = c(NA, -5L) )
需要为每个mtN_前缀的列生成对应总计列,比如mt1_total_vol是mt1_oranges_vol、mt1_pears_vol、mt1_apples_vol的行求和,以此类推。目前手动写mutate的方式扩展性差,希望通过预定义范围mt_range <- 1:6自动实现。
解决方案
方法1:使用dplyr的across函数(简洁高效)
利用across批量处理前缀,自动生成总计列:
library(dplyr) library(stringr) mt_range <- 1:6 dataset <- dataset %>% mutate( across( # 匹配所有mtN_开头的列模式 matches(paste0("mt", mt_range, "_", collapse = "|")), # 提取当前列的mtN_前缀,计算对应列的行和 ~ rowSums(select(., starts_with(str_extract(cur_column(), "^mt\\d+_"))), na.rm = FALSE), # 重命名新列为mtN_total_vol格式 .names = "{str_replace(.col, '_.*', '_total_vol')}" ) )
方法2:使用purrr函数式编程
通过map_dfc批量生成总计列后绑定到原数据:
library(dplyr) library(purrr) mt_range <- 1:6 # 批量生成各mtN的总计列 total_cols <- map_dfc(mt_range, function(n) { prefix <- paste0("mt", n, "_") dataset %>% select(starts_with(prefix)) %>% rowSums(na.rm = FALSE) %>% as.data.frame() %>% rename(!!paste0("mt", n, "_total_vol") := .) }) # 合并总计列到原数据集 dataset <- bind_cols(dataset, total_cols)
方法3:Base R循环(直观易懂)
用基础循环遍历每个mt编号,生成对应总计列:
mt_range <- 1:6 for(n in mt_range) { prefix <- paste0("mt", n, "_") total_col_name <- paste0("mt", n, "_total_vol") # 筛选当前前缀的列并计算行和 dataset[[total_col_name]] <- rowSums(dataset[, startsWith(names(dataset), prefix)], na.rm = FALSE) }
以上三种方法都能实现自动生成总计列的需求,后续新增mt7_等列时,只需调整mt_range的范围即可,无需修改核心逻辑。
内容的提问来源于stack exchange,提问作者y.a
相关产品推荐
相关产品推荐

