【问题标题】:Vectorizing R-loop for better performance向量化 R 循环以获得更好的性能
【发布时间】:2015-07-13 09:20:22
【问题描述】:

我在为 R 中的特定循环找到 矢量化 表示时遇到了问题。我的目标是提高循环的性能,因为它必须在算法中运行数千次。

我想在每行的向量“级别”定义的特定数组部分中找到最小值的位置。

例子:

Level = c(2,3)

令数组 X 的第一行为:c(2, -1, 3, 0.5, 4)

在行的1:Level[1] 范围内搜索最小值的位置(即(2, -1)),我得到一个 2,因为 -1 (Level[1]+1):(Level[1]+Level[2])(即(3, 0.5, 4))中搜索最小值的位置,我得到一个 4,因为 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])]))
  }
}

它工作正常,但我更喜欢性能更好的解决方案。有什么想法吗?

【问题讨论】:

  • 玩转max.col
  • 你能添加一个例子,Levels 有 3 个元素吗?第三个范围会是什么样子?
  • @Khashaa 正如在上一篇文章中看到的那样,你有正确的 clou。感谢您编辑我的帖子以提高可读性!

标签: r loops vectorization


【解决方案1】:

这将删除循环的外层:

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])
}

【讨论】:

  • 我只是想将相同的更改发布到您编辑的代码中。竖起大拇指,它有效!小速度测试表明,这个解决方案比我提出的代码快大约 33 倍!非常感谢您的解决方案!
【解决方案2】:

这是一个没有显式循环的“完全矢量化”解决方案:

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

【讨论】:

  • 完全矢量化了applysapply?
  • 感谢您解决问题!即使我应用并行化,@user3169080 的解决方案似乎也更快。
  • Touché, @ExperimenteR, *apply 只是一个循环包装器。但过度矢量化也是致命的罪过:burns-stat.com/pages/Tutor/R_inferno.pdf p24。 user3169080 的解决方案要快得多,但我很高兴并行化进一步改进了它。请注意,mclapply() 实际上不会在 Windows 上并行化(但在该平台上还有其他方法可以并行化)。
猜你喜欢
  • 2021-05-10
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-08
  • 1970-01-01
  • 1970-01-01
  • 2016-08-10
相关资源
最近更新 更多