2011-11-23 155 views
1

我正在運行一個for循環與兩個矩陣。一個matrix(A)具有〜100個字符串(例如,name1,name2,...,name100),並且只有一列。另一個matrix(B)大於A,包含值和字符串的行和列。在B矩陣的某些地方,匹配了A矩陣的每個名稱。我想提取並堆疊匹配的整行,並在輸出矩陣上使用矩陣A的特定字符串。from for循環適用於加速R

所以,我下面運行,

output <- NULL 
for(K in 1:nrow(A)){ 
    print(K) 
    for(cc in 1:nrow(B)){ 
    for(dd in 1:ncol(B)){ 
     if(toupper(A[K])==toupper(B[cc,dd])){ 
     output <- rbind(output,B[cc,]) 
     } 
    } 
    } 
} 

但實在是太慢了。如何讓循環在運行時間方面更高效?

+0

B矩陣真的是矩陣嗎?或者它是'data.frame'?一個「矩陣」只能有一種類型 - 所以所有的值都是字符串,然後... – Tommy

回答

0

這裏的一些想法:

A <- matrix(c('a','b','c','d'), ncol=1) 
B <- data.frame(z1=c('a','g','f','c'), z2=rnorm(4), z3=c('a','b','f','f')) 

id <- apply(B, 2, function(x) A %in% x) 
newB <- B[apply(id,1,sum)>0, ] 
+0

我得到「應用中的錯誤(kk,1,sum):object'kk'not found」? – Tommy

+0

kk實際上是id。我編輯了我的回答 –

5

速度問題不是因爲for-loop。 apply可能會更慢。您需要預先標註目標對象併爲索引分配值。

或者你需要考慮一個矢量化解決方案的喜歡...適用於Manuel的測試案例:

idx <- unique(which(toupper(as.matrix(B)) %in% toupper(A), arr.ind=TRUE) %% NROW(B)) 
idx[idx==0] <- 4 
    B[idx , ] 
    z1   z2 z3 
1 a 1.5623285 a 
4 c -1.2196311 f 
2 g 0.2551535 b 
+0

你的表達是錯誤的。你必須包含A向量,並且我認爲[,1]也是錯誤的。 –

+0

未經測試的算法往往是錯誤的。我會放入一個有效的。關心速度競爭? –

+0

你爲什麼分配idx [idx == 0] < - 4? –

4

這裏有一個快速的解決方案,應該給予同樣的輸出你的:

set.seed(13) 
A <- matrix(letters[1:5]) 
B <- matrix(sample(letters, 12, rep(T)), 4) 

x <- match(toupper(A), toupper(B), nomatch=0L) 
x <- (x[x>0L]-1L) %% nrow(B) + 1L 
output <- B[x, , drop=FALSE] 

它的工作原理是利用match找到B中的(矢量)標w這裏有一場比賽。然後它將這些索引轉換爲行索引,最後提取這些行。

..注意行B[2,]在輸出中包含兩次 - 這真的是你想要的嗎?如果沒有,更改最後一行:

output <- B[unique(x), , drop=FALSE] 

編輯一些時機。自從那個時代佔據主導地位以來,我刪除了toupper的電話號碼,@曼努埃爾拉蒙並沒有這麼稱呼。請注意,我們所有的輸出是不同的!所以一些調試可能是有保證的;-)

# Create huge A and B matrices 
set.seed(13) 
strs <- outer(letters, LETTERS, paste) 
A <- matrix(strs) 
B <- matrix(sample(strs, 1e7, rep(T)), 1e4) 

# My solution: 0.24 secs 
system.time({ 
x <- match(A, B, nomatch=0L) 
x <- (x[x>0L]-1L) %% nrow(B) + 1L 
output1 <- B[unique(x), , drop=FALSE] 
}) 

# @DWin's solution: 0.91 secs 
system.time({ 
idx <- unique(which(as.matrix(B) %in% A, arr.ind=TRUE) %% NROW(B)) 
idx[idx==0] <- 4 
output2 <- B[idx, , drop=FALSE] 
}) 

# @Manuel Ramon's solution: 0.89 secs 
system.time({ 
    id <- apply(B, 2, function(x) A %in% x) 
    output3 <- B[apply(id,1,sum)>0, ] 
}) 
+0

胡卡。我確信我的速度更快,尤其是自拉蒙有兩個應用循環以來。謝謝,@Tommy。我們顯然需要一組更好的調試用例。 –