首页 > 解决方案 > 如何在矩阵中按行将 0 分配给最小值(以快速/有效的方式)?

问题描述

一个有一个Lambda包含p列和n行的矩阵,并且对于每一行都希望将所有值分配给0除了第一列中的值和其他列中的最大值(在这个意义上p - 2,避开第一列之后的所有最小值)。

目前我正在使用for循环执行此操作,如下所示:

set.seed(60)
(Lambda = matrix(sample.int(30),5))
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]   19   20   27   18   15   25
[2,]   16   28    1    4   22    7
[3,]    2   10    8   23    3   12
[4,]    5    6    9   17   11   29
[5,]   26   30   24   13   14   21

m <- ncol(Lambda) - 2
for(ir in seq_len(nrow(Lambda))){
    Lambda[ir, match(tail(sort(abs(Lambda[ir, 2:ncol(Lambda)]), decreasing = TRUE), m), Lambda[ir,])] <- 0
}
Lambda
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]   19    0   27    0    0    0
[2,]   16   28    0    0    0    0
[3,]    2    0    0   23    0    0
[4,]    5    0    0    0    0   29
[5,]   26   30    0    0    0    0

很好,一个人得到了目标,但如果有很多行,这将成为一个问题。有没有不使用for循环的解决方案?可能是这样,lapply但我不确定它是否真的有效。也许data.table在转换矩阵之后?

谢谢!

标签: rperformancefor-loopmatrix

解决方案


所以有关

有没有不使用 for 循环的解决方案。

对于某些算法,您只需要编写一个 for 循环。没关系!为 lapply 之类的东西交换 for 循环并不是真正的性能改进(请参阅https://stackoverflow.com/a/42440872/4917834)。

不过,可以加快您的代码速度:

# your example
set.seed(60)
Lambda = matrix(sample.int(30),5)

original <- function(Lambda) {
  m <- ncol(Lambda) - 2
  for (ir in seq_len(nrow(Lambda))){
    Lambda[ir, match(tail(sort(abs(Lambda[ir, 2:ncol(Lambda)]), decreasing = TRUE), m), Lambda[ir,])] <- 0
  }
  Lambda
}
original(Lambda)

# a faster alternative
proposal <- function(Lambda) {

  nc <- ncol(Lambda)
  for (i in seq_len(nrow(Lambda))) {
    m <- which.max(abs(Lambda[i, -1L]))
    Lambda[i, (2:nc)[-m]] <- 0
  }
  Lambda
}
proposal(Lambda)

让我们对这两种方法进行基准测试:

bch <- bench::mark(
  original(Lambda),
  proposal(Lambda)
)
summary(bch, relative = TRUE)
# A tibble: 2 x 13
  expression              min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc 
  <bch:expr>            <dbl>  <dbl>     <dbl>     <dbl>    <dbl> <int> <dbl> 
1 original(Lambda)       25.7   24.1       1           1     1     1447     4
2 proposal(Lambda)        1      1        23.6         1     2.57  9997     3

所以proposal比您的原始解决方案快大约 24 倍(原始解决方案的中位时间为 313.8µs,建议为 13.1µs)。如果这还不够快,可能值得寻找在 C 或 C++ 中实现此功能的包。我玩过matrixStats但没有运气。或者,您可以将其移植到 C++ 中,Rcpp这样也可以加快代码速度。


推荐阅读