检查向量中的每个数字是否在R中另一个向量中的某些数字之间

时间:2016-02-19 13:14:36

标签: r intervals

假设我有两个向量,A和B. A有15个变量,B有28个变量。

A = c(13,14,29,31,32,39,42,51,59,61,68,91,102,109,120)

B = c(26,26,28,29,30,30,33,38,41,42,45,46,47,47,49,49,80,81,86,86,90,90,92,100,101,105,105,107)

我想要一个14乘27的矩阵Z,其中如果(B_j,B_ {j + 1}]与(A_i,A_ {i + 1}]重叠,则i by j条目为1。

例如,Z的(3,4)条目将是1,因为(29,31]和(29,30)重叠,30作为公共数。是否有快速计算方法?

我有以下代码:

Z = matrix(0, length(A)-1, length(B)-1)
for (i in 1:(length(A)-1)){
  nn = which(B > A[i] & B <= A[(i+1)])
  if (length(nn)>0){
    Z[i,(nn-1)] = 1}}

它运作良好,但我的A和B矢量通常包含30,000多个元素,而且速度非常慢。制作矩阵Z甚至需要不必要的长时间。任何人都可以帮忙吗?

理想情况下,有一个矢量化的解决方案可以解决这个问题,也可以从包中编写一个很好的函数来解决这个问题。

3 个答案:

答案 0 :(得分:3)

这是一个使用矩阵乘法的选项。正如所评论的那样,矩阵可能变得很大,你必须看看速度提升是否值得:

res1 <- outer(A, B, FUN = function(A, B){B > A})
res2 <- outer(A, B, FUN = function(A, B){B <= A})
dim(res1); dim(res2)
res3 <- (res1[-nrow(res1),] + res2[-1,]) == 2
image(res3)
dim(res3)

op <- par(mfcol=c(1,2))
image(Z, main="Z")
image(res3, main="res3")
par(op)

enter image description here

答案 1 :(得分:2)

如果关闭时间间隔[B_j,B_{j+1}][A_i, A_{i+1}]也适合您,您可以使用

A <- as.integer(c(13,14,29,31,32,39,42,51,59,61,68,91,102,109,120))
B <- as.integer(c(26,26,28,29,30,30,33,38,41,42,45,46,47,47,49,49,80,81,86,86,90,90,92,100,101,105,105,107))

DT_A <- data.table(A0 = A, A1 = shift(A, type = "lead"), key=c("A0", "A1"))[-length(A)]
DT_B <- data.table(B0 = B, B1 = shift(B, type = "lead"), key=c("B0", "B1"))[-length(B)]

ind_true <- foverlaps(DT_A, DT_B, type="any", mult="all", which=TRUE)[!is.na(yid)]

mat <- matrix(0, length(A)-1, length(B)-1)
mat[ind_true$xid, ind_true$yid] = 1

答案 2 :(得分:1)

这个答案使用矩阵索引并依赖于expand.grid,尽管它的实现速度要快得多。你滞后你的向量来创建A和B的矩阵,然后用一个做简单布尔检查的函数,我们可以用扩展网格索引到矩阵。然后它返回一个矩阵。

overlap = function(id,x1,x2){
  idA = id[,1]
  idB = id[,2]
  o = (x1[idA,1] >= x2[idB,1] & x1[idA,1] <= x2[idB,2]) | (x1[idA,2] >= x2[idB,1] & x1[idA,2] <= x2[idB,2]) |
    (x1[idA,1] <= x2[idB,1] & x1[idA,2] >= x2[idB,1]) | (x1[idA,1] <= x2[idB,2] & x1[idA,2] >= x2[idB,2])
  matrix(o,nrow=nrow(x1))
}

A = c(13,14,29,31,32,39,42,51,59,61,68,91,102,109,120)
nA = cbind(lag(A),A)[-1,]

B = c(26,26,28,29,30,30,33,38,41,42,45,46,47,47,49,49,80,81,86,86,90,90,92,100,101,105,105,107)
nB = cbind(lag(B),B)[-1,]

expand.grid.jc <- function(seq1,seq2) {
  cbind(Var1 = rep.int(seq1, length(seq2)), 
    Var2 = rep.int(seq2, rep.int(length(seq1),length(seq2))))
}

ids = expand.grid.jc(1:nrow(nA),1:nrow(nB))
overlap(ids,nA,nB)