基于dplyr实现按列值条件合并行:合并同一ID下Event1与Event2行并保留Event3行
解决方案:用dplyr优雅合并ID的前两行并保留第三行
我来帮你搞定这个需求,用dplyr完全可以优雅解决,不用头疼后续合并的麻烦!你的核心需求是每个ID下合并event1和event2的非NA值为一行(保留event1的标识),同时完整保留每个ID的event3行,之前用summarise_all的方法确实会带来后续join的困扰,我们换个思路直接在分组内处理:
具体思路
对每个ID分组后,拆分出两部分数据分别处理,再合并回一起:
- 合并event1和event2行:筛选出event为1和2的行,提取每列的非NA值(你的数据里每个score类列在这两行里只有一个有效值),然后把event固定为1;
- 保留原event3行:直接筛选出event为3的行,完全保留原始数据;
- 最后把这两部分在每个组内绑定,得到最终结果。
完整代码
library(dplyr) library(tibble) # 原始数据构造 id <- c(1,1,1,2,2,2,3,3,3,4,4,4,5,5,5) event <- c(1,2,3,1,2,3,1,2,3,1,2,3,1,2,3) score <- c(3,NA,1,3,NA,2,6,NA,1,8,NA,2,4,NA,1) score2 <- c(NA,4,1,NA,5,2,NA,0,3,NA,5,6,NA,8,7) df <- tibble(id, event, score, score2) # 核心处理代码 df_final <- df %>% group_by(id) %>% group_modify(function(.x, .y) { # 合并event1和event2的行 merged_row <- .x %>% filter(event %in% 1:2) %>% summarise( event = 1, # 合并后保留event1的标识 across(starts_with("score"), ~ .x[!is.na(.x)]) # 自动处理所有score开头的列,不管数量多少 ) # 保留event3的原始行 event3_row <- .x %>% filter(event == 3) # 绑定两部分数据 bind_rows(merged_row, event3_row) }) %>% ungroup() # 查看最终结果 df_final
代码细节说明
group_modify:dplyr里专门用来对每个分组做自定义处理的函数,完美适配这种组内拆分再合并的场景;across(starts_with("score"), ~ .x[!is.na(.x)]):用starts_with可以自动匹配所有score类列(哪怕你有300个),不需要逐个列写逻辑,自动提取每列的非NA值;- 全程在分组内完成所有操作,完全不需要后续的
join步骤,从根源上避免了大量.x/.y列的麻烦。
最终输出结果
运行后得到的结果和你期望的完全一致:
# A tibble: 10 x 4 id event score score2 <dbl> <dbl> <dbl> <dbl> 1 1 1 3 4 2 1 3 1 1 3 2 1 3 5 4 2 3 2 2 5 3 1 6 0 6 3 3 1 3 7 4 1 8 5 8 4 3 2 6 9 5 1 4 8 10 5 3 1 7
内容的提问来源于stack exchange,提问作者tomdidiot
相关产品推荐
相关产品推荐

