2015-07-13 109 views
3

我在找到一個向量化時遇到了問題 R中的特定循環表示我的目標是提高循環的性能,因爲它必須在循環中運行數千次算法。向量化R循環以獲得更好的性能

我想找到每個行由向量'Level'定義的特定數組部分中最低值的位置。

實施例:

Level = c(2,3) 

讓陣列X的第一行是:c(2, -1, 3, 0.5, 4)

在行(即(2, -1))的範圍1:Level[1]中搜索最低值的位置,我得到一個2,因爲-1 < 2和-1位於該行的第二個位置。然後,搜索第二個範圍(Level[1]+1):(Level[1]+Level[2])(即(3, 0.5, 4))中最低值的位置,我得到一個4,因爲0.5和0.5站在該行的第四個位置。我不得不在數組中的每一行執行此操作。

我對這個問題的解決方案的工作原理如下:

Level = c(2,3,3) #elements per section, here: 3 sections with 2,3 and 3 levels 
rows = 10 #number of rows in array X 
X = matrix(runif(rows*sum(Level),-5,5),rows,sum(Level)) #array with 10 rows and sum(Level) columns, here: 8 
Position_min = matrix(0,rows,length(Level)) #array in which the position of minimum values for each section and row are stored 
for(i in 1:rows){ 
for(j in 1:length(Level)){   #length(Level) is number of intervals, here: 3 
    if(j == 1){coeff=0}else{coeff=1} 
    Position_min[i,j] = coeff*sum(Level[1:(j-1)]) + which(X[i,(coeff*sum(Level[1:(j-1)])+1):sum(Level[1:j])] == min(X[i,(coeff*sum(Level[1:(j-1)])+1):sum(Level[1:j])])) 
    } 
} 

它工作正常,但我寧願一個解決方案具有更好的性能。有任何想法嗎?

+0

玩弄'ma x.col' – Khashaa

+0

你可以添加一個'Levels'有3個元素的例子嗎?第三個範圍如何? –

+0

@Khashaa正如你在上一篇文章中看到的那樣,你有正確的方塊。感謝您編輯我的帖子以增加易讀性! – Stromberg

回答

3

這將消除環路的外部級:

Level1=c(0,cumsum(Level)) 
for(j in 1:(length(Level1)-1)){ 
    Position_min[,j]=max.col(-X[,(Level1[j]+1):Level1[j+1]])+(Level1[j]) 
} 
+0

我只是想將相同的更改發佈到您編輯的代碼中。豎起大拇指,它的作品!小小的速度測試表明,這個解決方案比我提出的代碼快大約33倍!非常感謝您的解決方案!完全向量化的「應用」和「sapply」的 – Stromberg

3

這裏是一個「完全量化」的解決方案,沒有明確的循環:

findmins <- function(x, level) { 
    series <- rep(1:length(Level), Level) 
    x <- split(x, factor(series)) 
    minsSplit <- as.numeric(sapply(x, which.min)) 
    minsSplit + c(0, cumsum(level[-length(level)])) 
} 

Position_min_vectorized <- t(apply(X, 1, findmins, Level)) 
identical(Position_min, Position_min_vectorized) 
## [1] TRUE 

您可以通過你的矩陣獲得更好的性能列入清單,然後使用parallelmclapply()

X_list <- split(X, factor(1:nrow(X))) 
do.call(rbind, parallel::mclapply(X_list, findmins, Level)) 
## [,1] [,2] [,3] 
## 1  1 5 6 
## 2  2 3 6 
## 3  1 4 7 
## 4  1 5 6 
## 5  2 5 7 
## 6  2 4 6 
## 7  1 5 8 
## 8  1 5 8 
## 9  1 3 8 
## 10 1 3 8 
+3

? – ExperimenteR

+1

感謝您解決問題的方案!看來@ user3169080的解決方案即使應用並行化也會更快。 – Stromberg

+0

Touché,@ExperimenteR,* apply僅僅是一個循環包裝。但過度矢量化也是一個致命的錯誤:burns-stat.com/pages/Tutor/R_inferno.pdf p24。 user3169080的解決方案速度更快,但我很高興並行化進一步改進了它。請注意,'mclapply()'不會在Windows上實際並行化(但在該平臺上還有其他方法可以並行)。 –