在 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 倍重叠。
此外,还有一个需要考虑的用例:如何处理仅在一个点重叠的间隔,即一个间隔在另一个间隔开始的地方结束?
我有一个按行给定的 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 倍重叠。
此外,还有一个需要考虑的用例:如何处理仅在一个点重叠的间隔,即一个间隔在另一个间隔开始的地方结束?