检查向量中的每个数字是否在 R 中另一个向量中的某些数字之间
Check if each number in a vector is between some numbers in another vector in R
假设我有两个向量,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 x 27 矩阵 Z,如果 (B_j,B_{j+1}] 与 (A_i, A_{i+ 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 甚至会花费不必要的长时间。有人可以帮忙吗?
理想情况下,有一个向量化的解决方案来解决这个问题,或者有一个编写良好的函数可以像切蛋糕一样做这件事。
这是一个使用矩阵乘法的选项。正如所评论的那样,矩阵可能会变大,您必须看看速度改进是否值得:
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)
这个答案使用矩阵索引并依赖于 expand.grid
尽管它有更快的实现。您滞后向量以创建 A 和 B 的矩阵,然后使用一个执行简单布尔检查的函数,我们可以使用扩展网格对矩阵进行索引。然后它returns一个矩阵。
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)
如果闭区间 [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
假设我有两个向量,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 x 27 矩阵 Z,如果 (B_j,B_{j+1}] 与 (A_i, A_{i+ 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 甚至会花费不必要的长时间。有人可以帮忙吗?
理想情况下,有一个向量化的解决方案来解决这个问题,或者有一个编写良好的函数可以像切蛋糕一样做这件事。
这是一个使用矩阵乘法的选项。正如所评论的那样,矩阵可能会变大,您必须看看速度改进是否值得:
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)
这个答案使用矩阵索引并依赖于 expand.grid
尽管它有更快的实现。您滞后向量以创建 A 和 B 的矩阵,然后使用一个执行简单布尔检查的函数,我们可以使用扩展网格对矩阵进行索引。然后它returns一个矩阵。
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)
如果闭区间 [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