【问题标题】:Finding the overlapping range of a set of vectors in R在R中查找一组向量的重叠范围
【发布时间】:2021-03-22 21:54:15
【问题描述】:

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

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 ect 这样的通用包)解决方案是首选。我已经知道foverlaps (data.table) 和 IRranges,但它们似乎没有解决我的问题。对于奖励积分,如果存在阻止完全重叠的间隔,例如:rbind'ing c(20, 25)df 以上,则该函数仍应返回任何向量的最大可能重叠,即仍返回 c(3, 3.7)

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

EDIT EDIT:只有当它对所有范围都通用时,才应返回交集。 Henrik 链接的帖子中的解决方案 2 将区间组合在一起,即使组中并非所有区间都与其他区间相交

【问题讨论】:

    标签: r range overlap


    【解决方案1】:

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

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

    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)
    

    编辑:无重叠处理

    存在没有重叠的情况的OPhas pointed out需要单独识别和处理。所以我修改了代码:

    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
        }
      }]
    

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

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

    找到的最大重叠:6 个间隔中的 4 个

    对于 OP 的样本数据集没有重叠

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

    它会打印出来

    没有发现重叠

    警告

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

    此用例的示例数据:

    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 倍重叠。

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

    【讨论】:

    • 嗨,Uwe,这个解决方案看起来几乎完美 - 它适用于我的绝大多数案例。但是,当任何范围之间没有重叠时,它会抛出不正确的解决方案,例如dt &lt;- data.table(lb = c(3, 6, 10), ub = c(5, 9, 15)),返回数据集的全部范围,c(3, 15)。对此有何更正?
    • 虽然,与此同时,一个快速而肮脏的解决方案是检查返回的 DT 中的 N 列,如果该列中的最大值为 1,则表明没有重叠间隔,所以这确实提供了一种检测这些情况的方法
    • @JoeFlannerySutherland 实际上,我忽略了没有重叠的用例。针对您的 cmets,我已经改进了我的答案。
    • 感谢 Uwe,是的 - 我忽略了点重叠的情况。在我的情况下,点重叠应该被视为重叠
    猜你喜欢
    • 1970-01-01
    • 2020-08-26
    • 1970-01-01
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多