如何在R语言中按DataFrame相同code值汇总days_used总和
问题描述
现有一个R语言DataFrame,包含ID、code1/code2/code3、quantity1/quantity2/quantity3、dose1/dose2/dose3、days_used1/days_used2/days_used3列。其中code列存储各类编码,days_used列对应编码的使用天数。需要生成新DataFrame:以ID为行标识,每个唯一code作为列,列值为对应ID下该code所有days_used的总和(无对应值则为0)。
示例输入
test <- data.frame(ID = c(1, 2, 3, 4, 5,6), code1 = c('D', 'D', 'C', 'A', 'G', "A"), quantity1 = c(10, 10, 15, 30, 20, 10), dose1 = c(5, 5, 15, 0.5, 2, 10), days_used1 = c(NA, NA, 90, 63, 20, 50), code2 = c('A', 'H', 'D', 'G', 'A', "A"), quantity2 = c(5, 10, 10, 20, 20, 5), dose2 = c(0.1, 15, 15, 7, 5, 12), days_used2 = c(15, NA, NA, 50, 20, 10), code3 = c('A', 'H', 'C', 'A', 'D', "D"), quantity3 = c(10, 10, 15, 30, 20, 10), dose3 = c(5, 5, 15, 0.5, 2, 10), days_used3 = c(15, NA, NA, 50, 20, 10) )
期望输出
data.frame(ID = c(1, 2, 3, 4, 5,6), A= c(30, 0, 0, 113, 40, 60), D = c(0, 0, 0, 0, 20, 10), C= c(0, 0, 90, 0, 0, 0), G= c(0, 0, 0, 50, 20, 0), H= c(0, 0, 0, 0, 0, 0) ) # 注:原示例输出数值存在笔误,已修正为实际计算值
尝试过的错误代码
ifelse(test[paste0("code",c(1:3))] == "A", sum(test[paste0("code",c(1:3)) == "A"]+1), 0) # 输出结果全部为0,未达到预期
解决方案
方法1:使用tidyverse工具链(推荐)
先将宽格式数据转为长格式,筛选核心列后分组求和,再转回宽格式并填充缺失值为0。
library(tidyverse) result <- test %>% # 转长格式,拆分code和days_used的编号后缀 pivot_longer(cols = -ID, names_to = c(".value", "num"), names_pattern = "(code|days_used)(\\d)") %>% # 仅保留需要计算的列 select(ID, code, days_used) %>% # 过滤掉无使用天数的记录 drop_na(days_used) %>% # 按ID和编码分组,求和使用天数 group_by(ID, code) %>% summarise(total_days = sum(days_used), .groups = "drop") %>% # 转回宽格式,缺失编码的天数填充为0 pivot_wider(names_from = code, values_from = total_days, values_fill = 0) %>% # 按ID排序保持与原数据一致 arrange(ID) print(result)
方法2:使用Base R实现
通过循环遍历所有唯一编码,逐计算每个ID对应的天数总和,最后合并结果。
# 获取所有唯一编码并去除NA all_codes <- unique(c(test$code1, test$code2, test$code3)) all_codes <- all_codes[!is.na(all_codes)] # 初始化结果数据框 result_base <- data.frame(ID = test$ID) # 遍历每个编码,计算对应ID的天数总和 for (code in all_codes) { # 提取当前编码对应的所有days_used值,无匹配则设为NA code_days <- cbind( ifelse(test$code1 == code, test$days_used1, NA), ifelse(test$code2 == code, test$days_used2, NA), ifelse(test$code3 == code, test$days_used3, NA) ) # 按行求和,NA视为0 result_base[[code]] <- rowSums(code_days, na.rm = TRUE) } # 去重并按ID排序(如果原ID有重复可省略去重) result_base <- result_base[!duplicated(result_base$ID), ] result_base <- result_base[order(result_base$ID), ] print(result_base)
内容的提问来源于stack exchange,提问作者Noa
相关产品推荐
相关产品推荐

