2016-12-04 87 views
1

這可能有一個簡單的解決方案,但我仍然無法找到一個。我有兩個矩陣,其中一個的大小爲M1 =(4,2000000),另一個爲M2 =(4,209)。我想找到M2的每列與M1的所有列之間的元素交集的長度。R中兩個矩陣之間的元素交點

對於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循環?

謝謝!

+0

看來'tcrossprod(表(COL(M1),M1)> 0L,表(COL(M2),M2)> 0L)'是類似於你在做什麼。因爲你不關心出現的次數,可以用更有效的替換(矩陣(0L,ncol(M1),max(M1)),cbind替換table(col(M1),M1)> 0L' (rep(1:ncol(M1),each = nrow(M1)),c(M1)),1L)'或者甚至考慮使用考慮數據大小的稀疏矩陣 –

回答

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 
+0

現在添加基準,以便每個人都能更好地欣賞你的真棒解決方案:P –

+1

@DavidArenburg:我無法避免'ncol(M1)*長度(unique.default(M1) )'製表可能會帶來'無法分配內存'評論,將基準變成聖誕雪花...... :-) –

+0

是的,我想這是他矢量化解決方案的主要問題 - 與簡單循環相比,它們不是內存有效的。 –

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 

Upd大約吃了時間效率

所以總結一下,作爲OP在評論中提到,

  • 天真for解決方案大約需要20 mins
  • 我的解決方案約需36 secs
  • 這@alexis_laz的約12 secs

爲做同樣的工作。

+1

Thanks @ 989!我還在36秒內給出瞭解決方案,並在我的數據集上嘗試瞭解決方案。謝謝! – Andres

+1

@Andres很高興知道。所以它比天真的解決方案快得多。最好多謝一個投票解決方案;) – 989

+1

對不起@ 989,我的不好!忘了投票:) – Andres