【发布时间】:2020-10-26 18:37:45
【问题描述】:
我想知道是否可以对当前使用循环的函数进行矢量化。
给定一个示例矩阵:
m <- matrix(c(0,2,1,0,0,2,2,1,0), nrow = 3)
row.names(m) <- colnames(m) <- c("apple", "orange", "pear")
我想找到rowSums() 与rowSums() + colSums() 的比率最小值的项目。然后将识别为最小值的任何项目附加到向量z 并从m 中删除,然后重复该过程,直到所有项目都已在z 中订购。
以下循环运行良好:
loop.function <- function(mat){
nt <- nrow(mat)
z <- rep(NA, nt)
tmp.mat <- mat
for (i in 1:(nt - 1)) {
## ratio value
rv <- rowSums(tmp.mat) / (rowSums(tmp.mat) + colSums(tmp.mat))
## minimum of the ratio values (edited following comment)
min.rv <- which.min(rv)
## append item with minimum ratio value to ith position of z
z[i] <- names(rv)[min.rv]
## remove item appended to z from matrix
tmp.mat <- tmp.mat[-min.rv,-min.rv, drop = FALSE]
}
## append last remaining item of matrix to last position of z
z[nt] <- row.names(tmp.mat)
return(z)
}
但是这个循环很慢,考虑到一个足够大的问题。
我想知道是否可以创建一个矢量化等效于这个循环函数。如果这不可行,欢迎提出一些提高速度的想法。
重要
了解从m 中删除项目将影响后续比率值很重要。例如,m 的初始比率值为:
apple orange pear
0.4 0.6 0.5
在这种情况下,在第一次迭代中,apple 将从 m 中删除并附加到 z。
在下一次迭代中,剩余项的比率值为:
orange pear
0.3333333 0.6666667
因此您可以看到比率值取决于tmp.mat 中剩余的项目。
更新
loop.function() 与改进的循环函数的性能(详见下文)lf2() 与Rcpp 函数recmin():
Unit: microseconds
expr min lq mean median uq max neval cld
loop.function(m) 32.801 33.601 36.33707 34.201 34.9510 75.601 100 c
lf2(m) 20.800 21.701 24.81191 22.151 22.6505 82.200 100 b
recmin(m) 1.601 2.102 2.85100 2.701 3.1000 20.301 100 a
【问题讨论】:
-
你的真实数据有多大?
-
您好,感谢您的提问。我的问题不是矩阵太大,而是这个函数(必然)被算法调用了很多次,所以速度上的任何微小提升都可以极大地提高整个算法的性能
-
矩阵的一些大小估计可能会有所帮助。大概多少次?
-
当
min.rv有多个匹配项时会发生什么? -
尺寸:小矩阵(类似于 15x15),调用次数根据输入数据而变化,但通常调用此函数 1000 万次(算法单次运行中调用 1000 次,但用于不确定性估计,需要约 10k 次运行)。在 min.rv 上:从 min.rv 索引单个 min.rv(我在问题和示例代码中省略了这一点)
标签: r performance for-loop matrix vectorization