2012-02-16 65 views
5

我使用下面的腳本分析大型數據集:使嵌套循環更有效?

M <- c_alignment 
c_check <- function(x){ 
    if (x == c_1) { 
     1 
    }else{ 
     0 
    } 
} 
both_c_check <- function(x){ 
    if (x[res_1] == c_1 && x[res_2] == c_1) { 
     1 
    }else{ 
     0 
    } 
} 
variance_function <- function(x,y){ 
    sqrt(x*(1-x))*sqrt(y*(1-y)) 
} 
frames_total <- nrow(M) 
cols <- ncol(M) 
c_vector <- apply(M, 2, max) 
freq_vector <- matrix(nrow = sum(c_vector)) 
co_freq_matrix <- matrix(nrow = sum(c_vector), ncol = sum(c_vector)) 
insertion <- 0 
res_1_insertion <- 0 
for (res_1 in 1:cols){ 
    for (c_1 in 1:conf_vector[res_1]){ 
     res_1_insertion <- res_1_insertion + 1 
     insertion <- insertion + 1 
     res_1_subset <- sapply(M[,res_1], c_check) 
     freq_vector[insertion] <- sum(res_1_subset)/frames_total 
     res_2_insertion <- 0 
     for (res_2 in 1:cols){ 
      if (is.na(co_freq_matrix[res_1_insertion, res_2_insertion + 1])){ 
       for (c_2 in 1:max(c_vector[res_2])){ 
        res_2_insertion <- res_2_insertion + 1 
        both_res_subset <- apply(M, 1, both_c_check) 
        co_freq_matrix[res_1_insertion, res_2_insertion] <- sum(both_res_subset)/frames_total 
        co_freq_matrix[res_2_insertion, res_1_insertion] <- sum(both_res_subset)/frames_total 
       } 
      } 
     } 
    } 
} 
covariance_matrix <- (co_freq_matrix - crossprod(t(freq_vector))) 
variance_matrix <- matrix(outer(freq_vector, freq_vector, variance_function), ncol = length(freq_vector)) 
correlation_coefficient_matrix <- covariance_matrix/variance_matrix 

模型輸入會是這樣的:

1 2 1 4 3 
1 3 4 2 1 
2 3 3 3 1 
1 1 2 1 2 
2 3 4 4 2 

什麼我計算是每個國家的二項式方差在M[,i]中找到,每個州在M[,j]中找到。每一行都是該試驗的狀態,我想看看列的狀態是如何變化的。澄清:我找到兩個多項式分佈的協方差,但我通過二項式比較來完成。

輸入是一個4200 x 510矩陣,每列的c值平均約爲15。我知道for循環在R中非常緩慢,但我不確定在這裏如何使用apply函數。如果有人有建議,在這裏正確使用apply,我真的很感激。現在腳本需要幾個小時。謝謝!

+0

請問您可以添加一個小的數據集,你試圖得到什麼? – aatrujillob 2012-02-16 22:12:58

+0

@AndresT添加了更多信息。 – 2012-02-16 22:22:24

+0

你有沒有試過在編譯器中打開'loop unrolling'優化器? – 2012-02-16 22:36:34

回答

3

這不是真正的4路嵌套循環,而是你的代碼在每次迭代中增長內存的方式。這發生了4次,我在cbind和行上放置了# **。在這種情況下,R(以及Matlab和Python)中的標準建議是預先分配並填充它。這就是apply函數所做的。只要已知數量的結果,他們就會分配一個list,將每個結果分配給每個槽,然後將所有結果合併在一起。在你的情況下,你可以預先分配正確的大小矩陣,並在這4點(粗略地說)分配。這應該和apply系列一樣快,並且您可能會發現編碼更容易。

15

我想寫評論,但我有太多話要說。

首先,如果您認爲申請更快,請看Is R's apply family more than syntactic sugar?。它可能是,但它遠沒有保證。

接下來,請不要在您移動代碼時增長矩陣,這會讓代碼難以置信地變慢。預分配矩陣並填充它,這可以將您的代碼速度提高十倍以上。你通過你的代碼越來越多不同的向量和矩陣,這太瘋狂了(原諒我的強烈語音)

然後,看看?subset幫助頁面,並給予警告有:

這是一種便捷功能旨在交互使用。對於 編程,最好使用標準子集函數,如 [,特別是參數子集 的非標準評估可能會有意想不到的後果。

總是。使用。指數。

此外,您一次又一次重新計算相同的值。例如fre_res_2針對每個res_2和state_2計算的次數與組合res_1state_1的次數相同。這只是資源的浪費。從循環中取出不需要重新計算的內容,並將其保存在矩陣中,然後再次訪問。

哎呀,現在我在:請使用矢量化函數。再想想,看看你可以拖動循環了:這是我看到的你的計算的核心:

cov <- (freq_both - (freq_res_1)*(freq_res_2))/
(sqrt(freq_res_1*(1-freq_res_1))*sqrt(freq_res_2*(1-freq_res_2))) 

當我看到它,你可以構造一個矩陣freq_both,freq_res_1和freq_res_2並使用它們作爲那一行的輸入。這將是整個協方差矩陣(不要稱之爲cov,cov是一個函數)。退出循環。輸入快速代碼。

鑑於我不知道什麼是在c_alignment,我不會重寫你的代碼你,但你一定要擺脫思想的C-方式開始思考R.

讓這作爲開始:The R Inferno

+1

我希望我能給你+2!很好的答案和鏈接! – Justin 2012-02-16 23:13:42

+0

特別注意'The R Inferno'的圓圈2。 – 2012-02-17 09:26:00

+0

我第二+2 – 2012-02-17 10:33:18