R中两个矩阵之间的元素交集
Element intersection between two matrices in R
这可能有一个简单的解决方案,但我仍然找不到。我有两个矩阵,一个大小为 M1 = (4, 2000000),另一个大小为 M2=(4,209)。我想找到M2的每一列到M1的所有列之间的元素交集的长度。
对于 M2 中的一列,我这样做:
res <- apply(M1, 2, function(x) length(intersect(tmp, x)))
其中 tmp 是 M2 的第一列。
这大约需要 30 秒。为了加快 M2 所有列的计算速度,我执行 foreach:
list <- foreach(k=1:ncol(M2)) %dopar% {
tmp <- M2[,k]
res <- apply(M1, 2, function(x) length(intersect(tmp, x)))
}
这大约需要 20 分钟。
有没有办法用 apply 函数避免这个 foreach 循环?
谢谢!
鉴于你的矩阵维度,你可以这样做应该更快:
apply(m2, 2, function(x) colSums(m1==x[1] | m1==x[2] | m1==x[3] | m1==x[4]))
例如,假设:
m1
[,1] [,2] [,3]
[1,] 3 6 4
[2,] 9 8 11
[3,] 10 1 12
[4,] 2 5 7
m2
[,1] [,2]
[1,] 3 6
[2,] 2 7
[3,] 1 5
[4,] 8 4
然后,它会给你:
[,1] [,2]
[1,] 2 0
[2,] 2 2
[3,] 0 2
关于时间效率的更新
总结一下,正如 OP 在评论中提到的那样,
- 天真的
for
解决方案大约需要 20 mins
- 我的解决方案大约需要
36 secs
- @alexis_laz 约
12 secs
做同样的工作。
有数据:
set.seed(991)
M1 = matrix(sample(5, 50, TRUE), 5)
M2 = matrix(sample(5, 25, TRUE), 5)
你的解决方案returns:
op = sapply(1:ncol(M2),
function(k) apply(M1, 2, function(x) length(intersect(M2[, k], x))))
op
# [,1] [,2] [,3] [,4] [,5]
# [1,] 3 1 3 2 3
# [2,] 3 2 3 3 4
# [3,] 2 2 2 2 3
# [4,] 2 3 3 2 3
# [5,] 2 2 3 1 2
# [6,] 2 2 2 2 3
# [7,] 2 3 3 2 3
# [8,] 2 2 3 3 3
# [9,] 2 2 3 3 3
#[10,] 1 3 2 1 2
这就是
ans1 = tcrossprod(table(col(M1), M1) > 0L, table(col(M2), M2) > 0L)
returns.
all.equal(op, ans1, check.attributes = FALSE)
#[1] TRUE
因为我们不需要出现的次数,所以我们可以用简单的矩阵操作替换对 table
的昂贵调用:
m1 = matrix(0L, ncol(M1), max(M1))
m1[cbind(rep(1:ncol(M1), each = nrow(M1)), c(M1))] = 1L
m2 = matrix(0L, ncol(M2), max(M2))
m2[cbind(rep(1:ncol(M2), each = nrow(M2)), c(M2))] = 1L
ans2 = tcrossprod(m1, m2)
all.equal(op, ans2)
#[1] TRUE
对于你的情况,如果有机会避免内存限制,从制作稀疏表格开始似乎更合适:
library(Matrix)
sm1 = sparseMatrix(x = 1L,
i = rep(1:ncol(M1), each = nrow(M1)),
j = M1,
use.last.ij = TRUE)
sm2 = sparseMatrix(x = 1L,
i = rep(1:ncol(M2), each = nrow(M2)),
j = M2,
use.last.ij = TRUE)
ans3 = tcrossprod(sm1, sm2)
all.equal(op, as.matrix(ans3), check.attributes = FALSE)
#[1] TRUE
这可能有一个简单的解决方案,但我仍然找不到。我有两个矩阵,一个大小为 M1 = (4, 2000000),另一个大小为 M2=(4,209)。我想找到M2的每一列到M1的所有列之间的元素交集的长度。
对于 M2 中的一列,我这样做:
res <- apply(M1, 2, function(x) length(intersect(tmp, x)))
其中 tmp 是 M2 的第一列。
这大约需要 30 秒。为了加快 M2 所有列的计算速度,我执行 foreach:
list <- foreach(k=1:ncol(M2)) %dopar% {
tmp <- M2[,k]
res <- apply(M1, 2, function(x) length(intersect(tmp, x)))
}
这大约需要 20 分钟。
有没有办法用 apply 函数避免这个 foreach 循环?
谢谢!
鉴于你的矩阵维度,你可以这样做应该更快:
apply(m2, 2, function(x) colSums(m1==x[1] | m1==x[2] | m1==x[3] | m1==x[4]))
例如,假设:
m1
[,1] [,2] [,3]
[1,] 3 6 4
[2,] 9 8 11
[3,] 10 1 12
[4,] 2 5 7
m2
[,1] [,2]
[1,] 3 6
[2,] 2 7
[3,] 1 5
[4,] 8 4
然后,它会给你:
[,1] [,2]
[1,] 2 0
[2,] 2 2
[3,] 0 2
关于时间效率的更新
总结一下,正如 OP 在评论中提到的那样,
- 天真的
for
解决方案大约需要20 mins
- 我的解决方案大约需要
36 secs
- @alexis_laz 约
12 secs
做同样的工作。
有数据:
set.seed(991)
M1 = matrix(sample(5, 50, TRUE), 5)
M2 = matrix(sample(5, 25, TRUE), 5)
你的解决方案returns:
op = sapply(1:ncol(M2),
function(k) apply(M1, 2, function(x) length(intersect(M2[, k], x))))
op
# [,1] [,2] [,3] [,4] [,5]
# [1,] 3 1 3 2 3
# [2,] 3 2 3 3 4
# [3,] 2 2 2 2 3
# [4,] 2 3 3 2 3
# [5,] 2 2 3 1 2
# [6,] 2 2 2 2 3
# [7,] 2 3 3 2 3
# [8,] 2 2 3 3 3
# [9,] 2 2 3 3 3
#[10,] 1 3 2 1 2
这就是
ans1 = tcrossprod(table(col(M1), M1) > 0L, table(col(M2), M2) > 0L)
returns.
all.equal(op, ans1, check.attributes = FALSE)
#[1] TRUE
因为我们不需要出现的次数,所以我们可以用简单的矩阵操作替换对 table
的昂贵调用:
m1 = matrix(0L, ncol(M1), max(M1))
m1[cbind(rep(1:ncol(M1), each = nrow(M1)), c(M1))] = 1L
m2 = matrix(0L, ncol(M2), max(M2))
m2[cbind(rep(1:ncol(M2), each = nrow(M2)), c(M2))] = 1L
ans2 = tcrossprod(m1, m2)
all.equal(op, ans2)
#[1] TRUE
对于你的情况,如果有机会避免内存限制,从制作稀疏表格开始似乎更合适:
library(Matrix)
sm1 = sparseMatrix(x = 1L,
i = rep(1:ncol(M1), each = nrow(M1)),
j = M1,
use.last.ij = TRUE)
sm2 = sparseMatrix(x = 1L,
i = rep(1:ncol(M2), each = nrow(M2)),
j = M2,
use.last.ij = TRUE)
ans3 = tcrossprod(sm1, sm2)
all.equal(op, as.matrix(ans3), check.attributes = FALSE)
#[1] TRUE