在 R 中查找一组向量的重叠范围

Finding the overlapping range of a set of vectors in R

我有一个按行给定的 data.frame 区间,区间从第一列开始,区间在第二列结束。数字不是整数。如何找到所有间隔的重叠范围(如果有)。例如:

df <- cbind(c(1.5, 3, 2.1, 1), c(6, 5, 3.7, 10.1))
plot(1:11, ylim = c(0, 5), col = NA)
segments(x0 = c(1.5, 3, 2.1, 1), y0 = 1:4, x1 = c(6, 5, 3.7, 10.1), y1 = 1:4)
abline(v = 3, col  = "red", lty = 2)
abline(v = 3.7, col  = "red", lty = 2)

somefunc(df)

[1] 3  3.7

首选快速的基础 R(或 dplyr 等通用包)解决方案。我已经知道 foverlaps (data.table) 和 IRranges,但它们似乎没有解决我的问题。对于奖励积分,如果存在阻止完全重叠的间隔,例如:上面的 rbind'ing c(20, 25)df,则该函数仍应 return 任何向量的最大可能重叠, 即仍然 returning c(3, 3.7).

编辑:Henrik 链接的解决方案很好,但依赖于使用给定步骤(例如 seq(start, end by = 1))生成序列,然后减少它们以获得交集。我的间隔可能比这一步窄。理想情况下,我需要一个使用逻辑比较或类似方法运行的解决方案。链接页面中的第二个解决方案也不太正确(见下文)

EDIT EDIT:只有在所有范围都通用的情况下,交集才应该被return编辑。 Henrik 链接的 post 中的解决方案 2 将区间组合在一起,即使组中的所有区间并非都与其他区间相交

这是一个似乎 return 给定样本数据集的预期结果的解决方案。

它获取所有唯一区间端点的向量并计算它们相交的区间数(通过 在非等值连接中聚合 )。在交点数最多的点子集中,取范围

library(data.table)
# enhanced dataset with 2 additional intervals
dt <- fread("lb, ub
1.5,  6
3  ,  5
2.1,  3.7
1  , 10.1
8.3 , 12
20 , 25")

mdt <- dt[, .(b = unique(unlist(.SD)))]
res <- dt[mdt, on = .(lb <= b, ub >= b), .N, by = .EACHI][N == max(N), range(lb)]
res
[1] 3.0 3.7

可视化

library(ggolot2)
ggplot(dt) + 
  aes(x = lb, y = seq_along(lb), xend = ub, yend = seq_along(ub)) +
  geom_segment() +
  geom_vline(xintercept = res, col  = "red", lty = 2)

编辑:处理无重叠

没有重叠的OP需要单独识别和处理。所以我修改了代码:

mdt <- dt[, .(b = unique(unlist(.SD)))]
res <- dt[mdt, on = .(lb <= b, ub >= b), .N, by = .EACHI][
  N == max(N), {
    if (max(N) > 1) {
      cat("Maximum overlaps found:", max(N), "out of", nrow(dt), "intervals\n")
      range(lb)
    } else {
      cat("No overlaps found\n")
      NULL
    }
  }]

此代码将识别没有重叠的情况,并在这些情况下 return NULL。此外,还会打印一条消息。

在所有其他情况下,它将打印一条信息性消息,例如,

Maximum overlaps found: 4 out of 6 intervals

对于没有重叠的 OP 示例数据集

dt <- data.table(lb = c(3, 6, 10), ub = c(5, 9, 15))

它将打印

No overlaps found

警告

如果有多个解决方案,上面的代码将 return 整个范围,即第一个间隔的开始和最后一个间隔的结束,而不是单独间隔的列表。

此用例的示例数据:

dt <- fread("lb, ub
1.5,  6
3  ,  5
2.1,  3.7
1  , 10.1
11.5,  16
13  ,  15
12.1,  13.7
11  , 20.1
0   , 22
")

因此,3 和 3.7 之间有 5 倍重叠,13 和 13.7 之间有第二个 5 倍重叠。

此外,还有一个需要考虑的用例:如何处理仅在一个点重叠的间隔,即一个间隔在另一个间隔开始的地方结束?