识别 R 中连续重叠的片段
identify consecutively overlapping segments in R
我需要将重叠的片段聚合成单个片段,范围 所有连接的片段。
请注意,简单的重叠无法检测到非重叠但连接的段之间的连接,请参阅示例进行说明。如果在我的情节中我的部分会下雨,我正在寻找干燥的地面。
到目前为止,我通过迭代算法解决了这个问题,但我想知道是否有更优雅、更直接的方法来解决这个问题。我肯定不是第一个面对它的人。
我在考虑非等值滚动连接,但没能实现
library(data.table)
(x <- data.table(start = c(41,43,43,47,47,48,51,52,54,55,57,59),
end = c(42,44,45,53,48,50,52,55,57,56,58,60)))
# start end
# 1: 41 42
# 2: 43 44
# 3: 43 45
# 4: 47 53
# 5: 47 48
# 6: 48 50
# 7: 51 52
# 8: 52 55
# 9: 54 57
# 10: 55 56
# 11: 57 58
# 12: 59 60
setorder(x, start)[, i := .I] # i is just a helper for plotting segments
plot(NA, xlim = range(x[,.(start,end)]), ylim = rev(range(x$i)))
do.call(segments, list(x$start, x$i, x$end, x$i))
x$grp <- c(1,3,3,2,2,2,2,2,2,2,2,4) # the grouping I am looking for
do.call(segments, list(x$start, x$i, x$end, x$i, col = x$grp))
(y <- x[, .(start = min(start), end = max(end)), k=grp])
# grp start end
# 1: 1 41 42
# 2: 2 47 58
# 3: 3 43 45
# 4: 4 59 60
do.call(segments, list(y$start, 12.2, y$end, 12.2, col = 1:4, lwd = 3))
编辑:
太棒了,谢谢,cummax 和 cumsum 完成了这项工作,Uwe 的回答比 David 的评论稍微好一些。
end[.N]
可能会得到错误的结果,请尝试下面的示例数据 x
。
max(end)
在所有情况下都是正确的,而且速度更快。
x <- data.table(start = c(11866, 12696, 13813, 14011, 14041),
end = c(13140, 14045, 14051, 14039, 14045))
min(start)
和start[1L]
给的一样(因为x
是按start排序的),后者更快。
- 动态 grp 明显更快,不幸的是我需要分配 grp。
cumsum(cummax(shift(end, fill = 0)) < start)
明显快于 cumsum(c(0, start[-1L] > cummax(head(end, -1L))))
.
- 我没有测试包 GenomicRanges 解决方案。
您可以尝试 GenomicRanges
方法。在输出中,每一行都是一个组。
library(GenomicRanges)
x_gr <- with(x, GRanges(1, IRanges(start, end)))
as.data.table(reduce(x_gr, min.gapwidth=0))[,2:3]
start end
1: 41 42
2: 43 45
3: 47 58
4: 59 60
并且可以使用 Gviz
进行目视检查。这里必须知道该软件包是为生物学家和遗传信息而构建的。背后的图案是DNA碱基。因此,必须减去 1 个线段末端才能得到正确的图。
library(Gviz)
ga <- Gviz::GenomeAxisTrack()
xgr <- with(x, GRanges(1, IRanges(start, end = end - 1)))
xgr_red <- reduce(xgr, min.gapwidth=1)
ga <- GenomeAxisTrack()
GT <- lapply(xgr, GeneRegionTrack)
GT_red <- lapply(xgr_red, GeneRegionTrack, fill = "lightblue")
plotTracks(c(ga, GT, GT_red),from = min(x$start), to = max(x$start)+2)
OP 已请求将重叠的段聚合为一个包含所有连接段的段。
这是另一个使用 cummax()
和 cumsum()
来识别重叠或相邻段组的解决方案:
x[order(start, end), grp := cumsum(cummax(shift(end, fill = 0)) < start)][
, .(start = min(start), end = max(end)), by = grp]
grp start end
1: 1 41 42
2: 2 43 45
3: 3 47 58
4: 4 59 60
免责声明:我在 SO 的其他地方看到过这种巧妙的方法,但我记不起确切的位置。
编辑:
与一样,不需要单独创建grp
变量。这可以在 by =
参数中 即时 完成:
x[order(start, end), .(start = min(start), end = max(end)),
by = .(grp = cumsum(cummax(shift(end, fill = 0)) < start))]
可视化
OP 的情节可以修改以显示聚合的片段(快速和肮脏):
plot(NA, xlim = range(x[,.(start,end)]), ylim = rev(range(x$i)))
do.call(segments, list(x$start, x$i, x$end, x$i))
x[order(start, end), .(start = min(start), end = max(end)),
by = .(grp = cumsum(cummax(shift(end, fill = 0)) < start))][
, segments(start, grp + 0.5, end, grp + 0.5, "red", , 4)]
我需要将重叠的片段聚合成单个片段,范围 所有连接的片段。
请注意,简单的重叠无法检测到非重叠但连接的段之间的连接,请参阅示例进行说明。如果在我的情节中我的部分会下雨,我正在寻找干燥的地面。
到目前为止,我通过迭代算法解决了这个问题,但我想知道是否有更优雅、更直接的方法来解决这个问题。我肯定不是第一个面对它的人。
我在考虑非等值滚动连接,但没能实现
library(data.table)
(x <- data.table(start = c(41,43,43,47,47,48,51,52,54,55,57,59),
end = c(42,44,45,53,48,50,52,55,57,56,58,60)))
# start end
# 1: 41 42
# 2: 43 44
# 3: 43 45
# 4: 47 53
# 5: 47 48
# 6: 48 50
# 7: 51 52
# 8: 52 55
# 9: 54 57
# 10: 55 56
# 11: 57 58
# 12: 59 60
setorder(x, start)[, i := .I] # i is just a helper for plotting segments
plot(NA, xlim = range(x[,.(start,end)]), ylim = rev(range(x$i)))
do.call(segments, list(x$start, x$i, x$end, x$i))
x$grp <- c(1,3,3,2,2,2,2,2,2,2,2,4) # the grouping I am looking for
do.call(segments, list(x$start, x$i, x$end, x$i, col = x$grp))
(y <- x[, .(start = min(start), end = max(end)), k=grp])
# grp start end
# 1: 1 41 42
# 2: 2 47 58
# 3: 3 43 45
# 4: 4 59 60
do.call(segments, list(y$start, 12.2, y$end, 12.2, col = 1:4, lwd = 3))
编辑:
太棒了,谢谢,cummax 和 cumsum 完成了这项工作,Uwe 的回答比 David 的评论稍微好一些。
end[.N]
可能会得到错误的结果,请尝试下面的示例数据x
。max(end)
在所有情况下都是正确的,而且速度更快。x <- data.table(start = c(11866, 12696, 13813, 14011, 14041), end = c(13140, 14045, 14051, 14039, 14045))
min(start)
和start[1L]
给的一样(因为x
是按start排序的),后者更快。- 动态 grp 明显更快,不幸的是我需要分配 grp。
cumsum(cummax(shift(end, fill = 0)) < start)
明显快于cumsum(c(0, start[-1L] > cummax(head(end, -1L))))
.- 我没有测试包 GenomicRanges 解决方案。
您可以尝试 GenomicRanges
方法。在输出中,每一行都是一个组。
library(GenomicRanges)
x_gr <- with(x, GRanges(1, IRanges(start, end)))
as.data.table(reduce(x_gr, min.gapwidth=0))[,2:3]
start end
1: 41 42
2: 43 45
3: 47 58
4: 59 60
并且可以使用 Gviz
进行目视检查。这里必须知道该软件包是为生物学家和遗传信息而构建的。背后的图案是DNA碱基。因此,必须减去 1 个线段末端才能得到正确的图。
library(Gviz)
ga <- Gviz::GenomeAxisTrack()
xgr <- with(x, GRanges(1, IRanges(start, end = end - 1)))
xgr_red <- reduce(xgr, min.gapwidth=1)
ga <- GenomeAxisTrack()
GT <- lapply(xgr, GeneRegionTrack)
GT_red <- lapply(xgr_red, GeneRegionTrack, fill = "lightblue")
plotTracks(c(ga, GT, GT_red),from = min(x$start), to = max(x$start)+2)
OP 已请求将重叠的段聚合为一个包含所有连接段的段。
这是另一个使用 cummax()
和 cumsum()
来识别重叠或相邻段组的解决方案:
x[order(start, end), grp := cumsum(cummax(shift(end, fill = 0)) < start)][
, .(start = min(start), end = max(end)), by = grp]
grp start end 1: 1 41 42 2: 2 43 45 3: 3 47 58 4: 4 59 60
免责声明:我在 SO 的其他地方看到过这种巧妙的方法,但我记不起确切的位置。
编辑:
与grp
变量。这可以在 by =
参数中 即时 完成:
x[order(start, end), .(start = min(start), end = max(end)),
by = .(grp = cumsum(cummax(shift(end, fill = 0)) < start))]
可视化
OP 的情节可以修改以显示聚合的片段(快速和肮脏):
plot(NA, xlim = range(x[,.(start,end)]), ylim = rev(range(x$i)))
do.call(segments, list(x$start, x$i, x$end, x$i))
x[order(start, end), .(start = min(start), end = max(end)),
by = .(grp = cumsum(cummax(shift(end, fill = 0)) < start))][
, segments(start, grp + 0.5, end, grp + 0.5, "red", , 4)]