2017-04-06 254 views
1

我希望減少時間和內存使用(I以前使用外此,但它消耗更多的內存比我)通過減少迭代以創建一個對稱矩陣,即sol[i, j]相同sol[j, i]For循環創建對稱矩陣

到目前爲止我的代碼:

# Prepare input 
subss <- list(a = c(1, 2, 4), b = c(1, 2, 3), c = c(4, 5)) 
A <- matrix(runif(25), ncol = 5, nrow = 5) 
# Pre allocate memory 
sol <- matrix(nrow = length(subss), ncol = length(subss), 
      dimnames = list(names(subss), names(subss))) 
x <- 0 
for (i in seq_along(subss)) { 
    # Omit for the subsets I already calculated ? 
    for (j in seq_along(subss)) { 
     x <- x + 1 
     message(x) 

     # The function I use here might result in a NA 
     sol[i, j] <- mean(A[subss[[i]], subss[[j]]]) 
     sol[j, i] <- sol[i, j] # Will overwrite when it shouldn't 
    } 
} 

將使用9次迭代,如何避免他們做到這6次迭代?

我需要計算對稱值,因此this question不適用。此other one也不工作,因爲可能有很多組合,並且在某些時候它不能在內存中分配矢量。

+0

不行,首先它不會用我的subss,所以你提出什麼尺寸爲5×5不3x3的,第二我真正的函數,而不是意味着更復雜的 – Llopis

回答

0

for循環通常會比outer慢。嘗試字節編譯循環或在Rcpp中實現它。

subss <- list(a = c(1, 2, 4), b = c(1, 2, 3), c = c(4, 5)) 
set.seed(42) 
A <- matrix(runif(25), ncol = 5, nrow = 5) 

#all combinations of indices 
ij <- combn(seq_along(subss), 2) 

#add all i = j 
ij <- matrix(c(ij, rep(seq_along(subss), each = 2)), nrow = 2) 

#preallocate 
res <- numeric(ncol(ij)) 

#only one loop 
for (k in seq_len(ncol(ij))) { 

    message(k) 

    res[k] <- mean(A[subss[[ij[1, k]]], subss[[ij[2, k]]]]) 
} 
#1 
#2 
#3 
#4 
#5 
#6 

#create symmetric sparse matrix  
library(Matrix) 
sol <- sparseMatrix(i = ij[1,], j = ij[2,], 
        x = res, dims = rep(length(subss), 2), 
        symmetric = TRUE, index1 = TRUE) 
#3 x 3 sparse Matrix of class "dsCMatrix" 
#         
#[1,] 0.7764715 0.6696987 0.7304413 
#[2,] 0.6696987 0.6266553 0.6778936 
#[3,] 0.7304413 0.6778936 0.5161089 
+0

我會測試它是如何工作的。但subss是20000長,所以所有的組合都相當大。此外,我嘗試避免依賴關係,矩陣不稀疏,它帶來了什麼優勢?它更有效地存儲? – Llopis

+0

對稱矩陣稀疏。畢竟,你只需要存儲一個三角形和對角線。在我的系統上,計算'i'和'j'的4億組合需要大約一分鐘的時間。你的性能問題很可能是對你的功能的4億次呼叫。你應該認真考慮你是否真的需要這樣做,如果你這樣做,你應該使用Rcpp來完成任務。 – Roland

+0

時間是沒有太大的限制(以'outer'它得到的東西取決於數據〜5個小時完成),但記憶是(用'outer'與HTOP測量的過程達到91Gb),這就是爲什麼我認爲使用一個循環來防止所有的子集在內存中存在。但是,如您所說,我可能最終將功能移至Rcpp。 – Llopis

0

我發現了一種用普通的for循環:

x <- 0 
for (i in seq_along(subss)) { 
    for (j in seq_len(i)) { # or for (j in 1:i) as proposed below 
     x <- x + 1 
     message(x) 

     sol[i, j] <- mean(A[subss[[i]], subss[[j]]]) 
     sol[j, i] <- sol[i, j] 
    } 
} 
+1

'(j in 1:i)' – Roland

0
for (i in 1:length(subss)) { 
    for (j in 1:i) { 
    message(i, ' ', j, ' - ', mean(A[subss[[i]], subss[[j]]])) # Check iterations and value 
    sol2[i, j] <- sol2[j, i] <- mean(A[subss[[i]], subss[[j]]]) 
    } 
} 

我檢查你的腳本的價值觀和不是對稱的:

1 1 - 0.635455905252861 
1 2 - 0.638608284398086 
1 3 - 0.488700995299344 
2 1 - 0.568414432255344 
2 2 - 0.602851431118324 
2 3 - 0.516099992596234 
3 1 - 0.595461705311512 
3 2 - 0.656920690399905 
3 3 - 0.460815121419728 

礦值(同@ LLOPIS):

1 2 - 0.638608284398086 
1 3 - 0.488700995299344 
2 2 - 0.602851431118324 
2 3 - 0.516099992596234 
3 2 - 0.656920690399905 
3 3 - 0.460815121419728 
+0

我不明白這個答案從現有答案中得到了什麼改進。哪些值不等於哪些值? – Llopis

+0

原帖中的數值:[1 vs 3 - 0.488,3 vs 1 - 0.595],[1 vs 2 - 0.638,2 1 - 0.568] –