R

时间:2016-12-04 13:25:48

标签: r matrix apply

这可能有一个简单的解决方案,但我仍然找不到一个。我有两个矩阵,一个是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循环?

谢谢!

2 个答案:

答案 0 :(得分:3)

有数据:

set.seed(991)
M1 = matrix(sample(5, 50, TRUE), 5)
M2 = matrix(sample(5, 25, TRUE), 5)

您的解决方案返回:

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)

回报。

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

答案 1 :(得分:1)

考虑到你的矩阵维度,你可以做到这一点,这应该更快:

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
  • 的内容

做同样的工作。