R 查找两组向量之间的最小值(最快方式)

R 查找两组向量之间的最小值(最快方式),r,R,我有一个数据帧,它是一系列向量的开始和结束时间。我们有一组x向量和y向量,我想比较两个向量之间的最小距离。如果两个向量有任何重叠部分,则最小距离为0(在此应用程序中,不能有负距离) 下面是dataframe的外观(下面是一种获取它的简单方法): 所以我想在x向量上一行一行地进行,对每个x向量和所有y向量进行比较,找出两者之间的最小距离 下面我用嵌套的for循环来完成这一点,但我需要用更多的向量来重复多次,这样速度才会计数。这太慢了。完成这项任务最有效的方法是什么 所需输出: ## > ou

我有一个数据帧,它是一系列向量的开始和结束时间。我们有一组x向量和y向量,我想比较两个向量之间的最小距离。如果两个向量有任何重叠部分,则最小距离为0(在此应用程序中,不能有负距离)

下面是dataframe的外观(下面是一种获取它的简单方法):

所以我想在x向量上一行一行地进行,对每个x向量和所有y向量进行比较,找出两者之间的最小距离

下面我用嵌套的
for
循环来完成这一点,但我需要用更多的向量来重复多次,这样速度才会计数。这太慢了。完成这项任务最有效的方法是什么

所需输出:

## > out
## [1]  1  2  0 11  0  0
dat <- data.frame(
    x.start = c(3, 10, 19, 33, 100, 130),
    x.end = c(6, 14, 25, 33, 101, 150), 
    y.start = c(7, 19, 45, 66, 90, 134),
    y.end = c(8, 22, 45, 68, 101, 153)
)
我更愿意将其保留在BaseR中,但如果您有一种与操作系统无关的更快的方法,我是开放的

数据:

## > out
## [1]  1  2  0 11  0  0
dat <- data.frame(
    x.start = c(3, 10, 19, 33, 100, 130),
    x.end = c(6, 14, 25, 33, 101, 150), 
    y.start = c(7, 19, 45, 66, 90, 134),
    y.end = c(8, 22, 45, 68, 101, 153)
)
两组向量的可视化:

## > out
## [1]  1  2  0 11  0  0
dat <- data.frame(
    x.start = c(3, 10, 19, 33, 100, 130),
    x.end = c(6, 14, 25, 33, 101, 150), 
    y.start = c(7, 19, 45, 66, 90, 134),
    y.end = c(8, 22, 45, 68, 101, 153)
)

所以我想知道每个红色部分到最近y向量的最小距离(蓝色部分);虽然我看到x向量33:33和y向量45:45没有显示,但我认为这给出了问题的视觉描述

基准测试结果:运行记录


嵌套for循环答案:

## Convert start and end times to two lists of vectors
xvects <- mapply(":", dat[, 1], dat[, 2])
yvects <- mapply(":", dat[, 3], dat[, 4])

## Function to take vector x[i] and compare to all vector y    
FUN <- function(a, b) {
    vals <- abs(outer(a, b, "-"))
    if ((sum(vals) == 0) > 0) {
        return(0)
    }
    min(vals)
}

## Pre alot
out <- rep(NA, nrow(dat))

## Nested for loop
for (i in seq_along(xvects)) {

    outj <- rep(NA, nrow(dat))

    for (j in seq_along(yvects)) {

        outj[j] <- FUN(xvects[[i]], yvects[[j]])
    }

    out[i] <- min(outj)

}
##将开始和结束时间转换为两个向量列表

xvects不确定这是否最快。但这里有一种方法

apply(dat[,1:2], MARGIN=1, FUN=function(x) {
  min(apply(dat[,3:4], MARGIN = 1, FUN = function(y){
    X <- c(t(x))
    Y <- c(t(y))
    #Check if the two line segments overlap else find minimum distance between the 2 edges of each line segments
    if (diff(range(c(X,Y))) <=  diff(X) + diff(Y)){
      return(0)
    } else {
      return(min(abs(outer(Y, X, "-"))))
    }
  }))
})
## [1]  1  2  0 11  0  0
apply(dat[,1:2],边距=1,乐趣=function(x){
最小值(应用(dat[,3:4],裕度=1,乐趣=功能(y){

下面有两个选项。都使用。我相信不太简洁的选项(#2)会更快。我有兴趣看看基准测试

另外,请注意
by=
语句下面的注释。从示例数据来看,每个
x.start
值都有一个唯一的
x.end
值。如果是这种情况,则无需在
by
语句中包含
x.end
。否则,请更正该部分

  library(data.table)
  DT <- data.table(dummykey = "A", dat, key="dummykey")
  A <- DT[ , !c("y.start", "y.end"), with=FALSE][DT[, !c("x.start", "x.end"), with=FALSE], allow.cartesian=TRUE]

选择2

我认为最简单、最快的方法如下:

apply(dat, 1, function(d) {
  overlap <- (dat$y.end >= d[1] & dat$y.end <= d[2]) |
             (dat$y.start >= d[1] & dat$y.start <= d[2])
  if (any(overlap)) 0
  else min(abs(c(d[1] - dat$y.end[!overlap], dat$y.start[!overlap] - d[2])))
})

以下是一个更简单的解决方案(相对于我之前的答案),基于数据长而不宽的事实:

current <- c("x.start", "x.end")
comparedto <- c("y.start", "y.end")

apply(dat[, current], 1, function(r) {
  max(0, min(ifelse(r[[1]] > dat[, comparedto[[1]]], r[[1]]-dat[, comparedto[[2]]], dat[, comparedto[[1]]]-r[[2]])))
})
# [1]  1  2  0 11  0  0
current受上述启发(希望我没有误解OP):


alexis3“两个向量之间的最小距离”是什么意思?@HongOoi我的理解是,每个“向量”都是数字行上的一个间隔。你试图为每个x间隔找到最近的y间隔。例如,第一个x间隔是(3,6),所以最近的y间隔是(7,8)。这个“距离”然而,距离从x-区间到y-区间还很远…在示例中是1。@roliu听起来很准确。感谢帮助澄清。@Hing我添加了一个图片表示法,这样可能会有所帮助。我为我缺少数学术语而道歉,这可能会使我的问题更容易理解。哦,伙计…这是一个完全不同的问题;)但不管怎样,看起来你都将在多项式时间内。这仅仅是问题的本质。感谢你的解决方案。到目前为止,我对这两个解决方案进行了基准测试。也许这会激发其他人更快的解决方案。做得好。福特尼尔顿的编辑解决方案在多次复制时只稍微快一点。谢谢你的多次测试ple解决方案。不是最快的,但对每个人来说都是一次学习经历。+1
apply(dat, 1, function(d) {
  overlap <- dat$y.end >= d[1] & dat$y.start <= d[2]
  if (any(overlap)) 0
  else min(abs(c(d[1] - dat$y.end[!overlap], dat$y.start[!overlap] - d[2])))
})
current <- c("x.start", "x.end")
comparedto <- c("y.start", "y.end")

apply(dat[, current], 1, function(r) {
  max(0, min(ifelse(r[[1]] > dat[, comparedto[[1]]], r[[1]]-dat[, comparedto[[2]]], dat[, comparedto[[1]]]-r[[2]])))
})
# [1]  1  2  0 11  0  0
alexis3 <- function()
{                   
 fun <- function(x1, x2, yvec1 = dat$y.start, yvec2 = dat$y.end) 
 { 
  if(any(c(yvec1, yvec2) %in% seq(x1, x2))) return(0)
  else min(abs(outer(c(x1, x2), c(yvec1, yvec2), `-`))) 
 } 

 mapply(fun, x1 = dat$x.start, x2 = dat$x.end)
}

#> alexis3()
#[1]  1  2  0 11  0  0