如何在R中编写循环按连续相同abs.sum值合并数据框行?
合并连续相同abs.sum值的数据框行(按chr分组)
需求说明
针对每个chr分组,将连续具有相同abs.sum值的行合并,保留该组最小的start值和最大的end值。
测试数据
r1 <- c(1, 1,1000,2) r2 <- c(1, 1001,2000, 2) r3 <- c(1, 2001,3000, 2) r4 <- c(1, 3001,4000, 1) r5 <- c(1, 4001,5000, 3) r6 <- c(1, 5001,6000, 3) r7 <- c(2, 1,1000,2 ) r8 <- c(2, 1001,2000, 1) r9 <- c(2, 2001,3000, 2) r10 <- c(2, 3001,4000, 1) r11 <- c(2, 4001,5000, 1) test <- rbind(r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11) test <- as.data.frame(test) colnames(test) <- c("chr", "start","end", "abs.sum") rownames(test) <- NULL
原始数据框结构:
chr start end abs.sum 1 1 1 1000 2 2 1 1001 2000 2 3 1 2001 3000 2 4 1 3001 4000 1 5 1 4001 5000 3 6 1 5001 6000 3 7 2 1 1000 2 8 2 1001 2000 1 9 2 2001 3000 2 10 2 3001 4000 1 11 2 4001 5000 1
期望结果:
chr start end abs.sum 1 1 1 3000 2 2 1 3001 4000 1 3 1 4001 6000 3 4 2 1 1000 2 5 2 1001 2000 1 6 2 2001 3000 2 7 2 3001 5000 1
错误尝试及问题
尝试编写的for循环:
for (i in 1:nrow(test)) { if (test$abs.sum[i] == test$abs.sum[i + 1]) { test$end[i] <- test$end[i+1] test <- test[-i + 1] test <- test[-(i + 1),] } }
运行后报错:
Error in if (test$abs.sum[i] == test$abs.sum[i + 1]) { :
argument is of length zero
错误原因:循环中直接修改了数据框的行数,导致后续迭代时i+1超出数据框的行范围;同时删除行的逻辑错误(test[-i + 1]语法错误,且连续删除行会打乱索引)。
解决方法
方法一:使用dplyr包(推荐)
无需手动写循环,用dplyr的分组和聚合功能即可快速实现,核心是给连续相同的abs.sum值组生成分组标识:
library(dplyr) test_result <- test %>% group_by(chr) %>% # 生成连续相同abs.sum的分组标识 mutate(grp = cumsum(abs.sum != lag(abs.sum, default = abs.sum[1]))) %>% group_by(chr, grp, abs.sum) %>% # 聚合取最小start、最大end summarize(start = min(start), end = max(end), .groups = "drop") %>% select(chr, start, end, abs.sum) # 调整列顺序 print(test_result)
运行后即可得到期望结果。
方法二:手动编写循环实现
如果一定要用循环,建议从后往前遍历(避免删除行后索引混乱),同时按chr分组处理:
# 复制原始数据避免修改原数据 test_loop <- test i <- nrow(test_loop) while (i > 1) { # 仅当当前行和上一行chr相同、abs.sum相同时合并 if (test_loop$chr[i] == test_loop$chr[i-1] && test_loop$abs.sum[i] == test_loop$abs.sum[i-1]) { # 更新上一行的end为当前行的end test_loop$end[i-1] <- test_loop$end[i] # 删除当前行 test_loop <- test_loop[-i, ] } i <- i - 1 } print(test_loop)
这种写法从最后一行开始往前检查,避免了删除行后后续索引失效的问题,同样能得到正确结果。
内容的提问来源于stack exchange,提问作者Louise
相关产品推荐
相关产品推荐

