【问题标题】:identify consecutively overlapping segments in R识别 R 中连续重叠的段
【发布时间】:2019-02-05 02:18:54
【问题描述】:

我需要将重叠的段聚合成一个段,范围是所有连接的段

请注意,简单的 foverlaps 无法检测非重叠但连接的段之间的连接,请参阅示例以进行说明。如果在我的地块上会下雨,我正在寻找干涸的土地。

到目前为止,我通过迭代算法解决了这个问题,但我想知道是否有更优雅和更直接的方法来解决这个问题。我肯定不是第一个面对它的人。

我在考虑非等值滚动连接,但未能实现

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 的回答比 Davids 的评论略好。

  • end[.N] 可能会得到错误的结果,请尝试下面的示例数据xmax(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 on the fly 明显更快,不幸的是我需要分配 grp。
  • cumsum(cummax(shift(end, fill = 0)) &lt; start) 明显快于 cumsum(c(0, start[-1L] &gt; cummax(head(end, -1L))))
  • 我没有测试包 GenomicRanges 解决方案。

【问题讨论】:

  • x[, .(start[1L], end[.N]), by = .(grp = cumsum(c(0, start[-1L] &gt; cummax(head(end, -1L)))))] 可以工作。基本上是我的解决方案的 data.table 版本here

标签: r data.table grouping overlap locf


【解决方案1】:

您可以尝试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)

【讨论】:

  • 这个组正是他要找的。​​span>
  • 在您的编辑中您仍在使用x$grp=..... 这是组的手动输入。应该不是这样的
  • @Jimbou 你的第一个声明明确指出#add the grouping 但是我们没有分组.. 我们应该创建/获取分组。查看Uwe提供的答案
  • @Onyambu 我删除了我的第一个答案。现在你只能通过startend,然后你就得到了预期的结果。满意吗?
  • 这解决了这个问题。喜欢它
【解决方案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 的其他地方看到过这种聪明的方法,但我不记得确切的位置。

编辑

作为David Arenburg has pointed out,不需要单独创建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)]

【讨论】:

  • 不需要创建grp,直接传入by即可。
  • @DavidArenburg 没有提供grp,这是问题的主要目的。创建组
  • 您的意思是 OP 想要原始数据中的 grp?也许你是对的
  • @Onyambu OP 已请求 将重叠段聚合成一个包含所有连接段的单个段。
  • 我明白了.. 虽然刚刚看到 OP 写了 我正在寻找的分组。它仍然回答了解决方案
猜你喜欢
  • 2018-11-26
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
相关资源
最近更新 更多