R语言按ID分组合并res变量值并保留其他列的实现方法
问题描述
给定如下R语言DataFrame:
data=data.frame(id=c("a", "a", "a", "b", "b", "c", "c", "c", "c", "d"), val1=c(0,0,0,89,89,5,5,5,5,4), val2=c(6,6,6,9,9,8,8,8,8,9), Clin3=c(11,11,11,5,5,3,3,3,3,3), Clin4=c(9,9,9,78,78,0,0,0,0,1), res=c("Pal:7", "Pal:8", "Pml:7", "Poi:2", "Oiu:5", "Rtf:4", "Pml:8", "Oiu:9", "Edr:5", "Pal:8"))
数据预览:
id val1 val2 clin3 clin4 res 1 a 0 6 11 9 Pal:7 2 a 0 6 11 9 Pal:8 3 a 0 6 11 9 Pml:7 4 b 89 9 5 78 Poi:2 5 b 89 9 5 78 Oiu:5 6 c 5 8 3 0 Rtf:4 7 c 5 8 3 0 Pml:8 8 c 5 8 3 0 Oiu:9 9 c 5 8 3 0 Edr:5 10 d 4 9 3 1 Pal:8
需求:按id分组,将res列的取值用下划线合并,同时保留其他变量的取值(同一id分组内其他变量值均一致)。
用户尝试的代码仅保留了id和合并后的res,丢失了其他列:
data %>% group_by(id) %>% summarise(across(res, ~ paste(unique(.x[!is.na(.x)]), collapse = ", ")))
期望输出:
id val1 val2 clin3 clin4 res 1 a 0 6 11 9 Pal:7_Pal:8_Pml:7 2 b 89 9 5 78 Poi:2_Oiu:5 3 c 5 8 3 0 Rtf:4_Pml:8_Oiu:9_Edr:5 4 d 4 9 3 1 Pal:8
解决方案
由于同一id分组内,val1、val2、Clin3、Clin4的取值唯一,因此可以在汇总时对这些列取第一个/唯一值,同时合并res列:
方法1:逐个指定列处理
library(dplyr) data %>% group_by(id) %>% summarise( val1 = first(val1), val2 = first(val2), Clin3 = first(Clin3), Clin4 = first(Clin4), res = paste(res, collapse = "_") ) %>% ungroup()
注:first()可替换为unique()或last(),因分组内值一致,结果无差异。若res存在重复值需去重,可改为paste(unique(res), collapse = "_")。
方法2:批量处理非res列
当非res列数量较多时,用across批量处理更高效:
data %>% group_by(id) %>% summarise( across(-res, first), # 对除res外的所有列取第一个值 res = paste(res, collapse = "_") ) %>% ungroup()
方法3:使用reframe(dplyr 1.1.0+)
若使用dplyr 1.1.0及以上版本,reframe可自动保留分组键,写法更简洁:
data %>% group_by(id) %>% reframe( across(-res, first), res = paste(res, collapse = "_") )
内容的提问来源于stack exchange,提问作者Av65
相关产品推荐
相关产品推荐

