2016-11-29 113 views
0

我試圖優化r中的一個循環,該循環計算向量中關於數據幀中每一行的每個元素的字符串匹配數量。在小數據集中,它工作得很好(〜15分鐘; 11列,914行)。但是,運行龐大的數據集需要數天(914列,18.000行)。這是我非常基本的循環:加速r循環字符串匹配(矢量與數據幀)

for (j in 1: dim(pddbnh)[1]){ 
    for (i in 1:dim(pidf)[1]){ 
    richa[i,j] <- length(pidf[i,][pidf[i,] == row.names(pddbnh)[j] ]) 
    } 
} 

我想知道是否有人知道如何使用其他方法(如矢量化)優化此循環。任何解決方案將非常感謝!

UPDATE 這是一個小數據集。這是最快的國家之一

df<-data.frame(replicate(10,sample(c("sp1", "sp2"),10,rep=TRUE))) 
vec<-c("sp1", "sp2") 
richa <- data.frame() 

    for (j in 1:length(vec)){ 
    for (i in 1:dim(df)[1]){ 
    richa[i,j] <- length(df[i,][df[i,] == vec[j] ]) 
    } 
    } 
+1

是的,我可能知道如何做到這一點。請爲測試提供一個最小可重現的示例。 – Roland

+0

謝謝!以下是兩個文件:https://www.dropbox.com/s/vvksp7c1kerqjbq/pddbnh.csv?dl=0 https://www.dropbox.com/s/zjt9shku0gjf03t/pidf.csv?dl=0 – CristianR

+0

(顯然你還沒有對SO進行徹底搜索,因爲有許多問答關於提高for循環的性能。)詢問'['處理'[pidf [i,] == row.names(pddbnh)[ j]]似乎註定要失敗。該參數的結果將在強制後爲0或1(因此應該出現關於長度爲零的替換的錯誤)。也許你應該解釋你實際嘗試的是什麼。 –

回答

3

下面是使用lapply的方法(參見下面的更快):

richa <- lapply(X = vec, FUN = function(x) rowSums(df == x)) 
richa <- do.call(cbind, richa) 

快速microbenchmark上的小數據集您提供展示了這個約10倍比你的快for循環方法。

只需要添加一下,對於真正的大數據集,使用parallel::mclapplyplyr::laply(與parallel = TRUE)可以很容易地爲多線程。它需要一些額外的工作,但對於那些18000 x 914數據集可能是值得的。

編輯要添加:因爲你有幾個循環去那裏(並且因爲我正在學習Rcpp,並且渴望練習),所以這裏有一個更快的解決方案,使用Rcpp。下面是函數的定義(這需要進行一次編譯):

Rcpp::cppFunction(' IntegerMatrix charCrossCheck(CharacterMatrix df, 
          CharacterVector vec) { 

       IntegerMatrix output(df.nrow(), vec.size()); 

       for (int j=0; j < vec.size(); ++j){ 
        for (int i=0; i < df.nrow(); ++i){ 
         int count = 0; 
         for(int k=0; k < df.ncol(); k++){ 
          if(df(i,k) == vec[j]) { 
           count++; 
          } 
         } 
         output(i,j) = count; 
        } 
       } 
       return output; 

       } ') 

然後你就可以調用函數:

richa <- charCrossCheck(as.matrix(df), vec) 

Rcpp是非常快的在這裏。你的非常小的樣本微基準展示了3倍比我lapply解決方案比你for循環中R.更更快以上,約38X快

有趣的是,擴大了輸入數據輸出到df尺寸4000x4000,並且vec的長度爲10時,Rcpplapply方法都在非常相似的時間(分別爲3.4秒和3.9秒)完成作業。在您提到的數據集(18000行×914列,長度爲vec,長度爲2)的數據集中,兩種解決方案均低於1秒。這兩種方法都不錯!

+0

兩種方法都比較快!這太神奇了,幫助我很多。我會試圖弄清楚兩個實現的細節。我很驚訝! – CristianR

+0

@CristianR太棒了!如果能幫助解決您的問題,請將答案標記爲已接受。 – rosscova