2015-07-13 107 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上实际并行化(但在该平台上还有其他方法可以并行)。 –