2012-03-05 122 views
3

我有一個雙重循環,我不僅不喜歡,但需要14天才能在我的計算機上運行,​​因爲它將以大約.1212次的迭代超過3200條記錄和1090個變量。比較記錄結果和雙循環

可重複性較小的位。它只是檢查兩個記錄之間同一列中有多少個數字,不包括NA。然後它將結果附加到原始數據框。

y <- data.frame(c(1,2,1,NA,NA),c(3,3,3,4,NA),c(5,4,5,7,7),c(7,8,7,9,10)) 
resultdf <- NULL 
for(i in 1:nrow(y)) 
{ 
    results <- NULL 
    for(j in 1:nrow(y)) 
    { 
    results <- c(results,sum((y[i,]==y[j,]),na.rm=TRUE)) 
    } 
    resultdf <- cbind(resultdf,results) 
} 
y <- cbind(y,resultdf) 

我有重複計算,可能可以避免離開大約7天。

如果我理解正確,幾個應用函數在C中可能會更快。儘管如此,我還沒有得到任何工作。我也很好奇,如果有一個包會跑得更快。任何人都可以幫助加速計算?

謝謝!

+2

你應該首先看看在開始之前將'y'轉換爲矩陣的速度有多快......我認爲重新排列'outer(y,y,「== 「)'''適當地,並採取行或列的總結,但我沒​​有時間去處理它現在... – 2012-03-05 21:15:51

+0

...我假設通過」重複計算「你談論循環所有(我,j )而不僅僅是較低或較高的三角形...... – 2012-03-05 21:21:23

+0

更改爲矩陣將整個事件加速至16分鐘左右。謝謝你的提示!是的,它重複計算而不是計算其中一個三角形。你會怎麼做呢?我猜它是在循環結尾添加i < - i + 1來重新計算下邊界,但我從來沒有這樣做過。你如何將它複製到另一個三角形? – ARobertson 2012-03-05 21:37:34

回答

3

我已經創建的數據對您的規格,並使用@ BenBolker的建議,關於使用矩陣:

> y <- matrix(sample(c(1:9, NA), 3200 * 1090, replace = TRUE), 
+    nrow = 3200, ncol = 1090) 

,並比較了計算時間爲三個不同的實現方式:

f1被提出@Andrei:

> f1 <- function(y)apply(y, 1, function(r1) 
+     apply(y, 1, function(r2)sum(r1==r2, na.rm=TRUE))) 

> system.time(r1 <- f1(y)) 
    user system elapsed 
523.51 0.77 528.73 

f2有人建議通過@VincentZoonekynd:

> f2 <- function(y) { 
+ f <- function(i,j) sum(y[i,] == y[j,], na.rm=TRUE) 
+ d <- outer(1:nrow(y), 1:nrow(y), Vectorize(f)) 
+ return(d) 
+ } 
> system.time(r2 <- f2(y)) 
    user system elapsed 
658.94 1.96 710.67 

f3超過上三角雙環流通過@BenBolker的建議。它也比你們的操作效率更好,因爲它預先分配輸出矩陣:

> f3 <- function(y) { 
+ result <- matrix(NA, nrow(y), nrow(y)) 
+ for (i in 1:nrow(y)) { 
+  row1 <- y[i, ] 
+  for (j in i:nrow(y)) { 
+  row2 <- y[j, ] 
+  num.matches <- sum(row1 == row2, na.rm = TRUE) 
+  result[i, j] <- num.matches 
+  result[j, i] <- num.matches 
+  } 
+ } 
+ return(result) 
+ } 

> system.time(r3 <- f3(y)) 
    user system elapsed 
167.66 0.08 168.72 

所以雙迴路是最快的所有三個,雖然不如優雅和緊湊其他兩個答案。

+0

一個有趣的基準。通常應用函數的工作速度比循環快得多,例如如sapply(矢量,樂趣),但顯然不是在這種情況下。 – Andrei 2012-03-06 07:03:31

+1

@Andrei,這通常是不正確的,請參閱http://stackoverflow.com/questions/2275896/is-rs-apply-family-more-than-syntactic-sugar。 – flodel 2012-03-06 12:14:41

+0

感謝您的鏈接。我相信應用函數更快,但現在我開始思考我的信念,我找不到任何理由:) – Andrei 2012-03-07 09:21:20

2

的確,您可以使用apply函數。鑑於早前暗示矩陣工作更快,我會嘗試:

ym <- as.matrix(y) 
resultdf <- apply(ym, 1, function(r1) apply(ym, 1, function(r2) sum(r1==r2, na.rm=TRUE))) 
3

這裏是另一個解決方案,使用outer

f <- function(i,j) sum(y[i,] == y[j,], na.rm=TRUE) 
d <- outer(1:nrow(y), 1:nrow(y), Vectorize(f)) 
1

你可以擺脫內環(使用yf3從@ flodel的答案)的:

ty <- t(y) 
ix <- rep(1:nrow(y),each = ncol(y)) 
f4 <- function(y){ 
    result <- matrix(0L, nrow(y), nrow(y)) 
    for(r in 1:nrow(y)) 
     result[r,] <- rowsum(as.numeric(ty == y[r,]), ix, na.rm = T) 
    result 
} 



> system.time(out <- f4(y)) 
    user system elapsed 
52.616 21.061 74.000 
> system.time(out <- f3(y)) 
    user system elapsed 
244.751 0.136 244.954 
> 

它實際計算兩次同樣的事情的一個額外的工作,但仍快5倍。通過使用rowsum的內部工作,您可以再快4倍。例如,請參閱此question

+0

我已經測試過,但沒有得到與您一樣的計算時間。在我的機器上,'f4'慢5倍*。你能確認還是你在使用一些非標準庫,如ATLAS/MKL/etc? 如果我使用result [r,] < - colSums(ty == y [r,],na.rm = TRUE),我確實得到了不錯的速度提升('f4'快於'f3'的40%)' 。 – flodel 2012-03-07 04:29:43

+0

@ flodel,一切都很標準,gnu linux R13.1在這裏。你有沒有像你的例子那樣用大矩陣測試它?對於小矩陣,f4確實比較慢; 'rowsum'是爲速度而編寫的,更適用於很多組和許多列。 – VitoshKa 2012-03-07 11:14:36

+0

我已經用OP中提到的3200×1090矩陣進行了測試。 – flodel 2012-03-07 12:11:51