与常规矩阵类相比,Matrix 包中的提取速度非常慢

Moh*_*sri 4 performance r matrix sparse-matrix

这是一个比较使用Matrix 包和常规R 基矩阵类从大型稀疏矩阵和密集矩阵中提取行的示例。

对于稠密矩阵,基类的速度几乎快 395 倍matrix:

library(Matrix)
library(microbenchmark)

## row extraction in dense matrices
D1<-matrix(rnorm(2000^2), 2000, 2000)
D2<-Matrix(D1)
> microbenchmark(D1[1,], D2[1,])
Unit: microseconds
    expr      min        lq       mean    median       uq      max neval
 D1[1, ]   14.437   15.9205   31.72903   31.4835   46.907   75.101   100
 D2[1, ] 5730.730 5744.0130 5905.11338 5777.3570 5851.083 7447.118   100
Run Code Online (Sandbox Code Playgroud)

对于稀疏矩阵,又几乎支持了 63 倍matrix。

## row extraction in sparse matrices
S1<-matrix(1*(runif(2000^2)<0.1), 2000, 2000)
S2<-Matrix(S1, sparse = TRUE)
microbenchmark(S1[1,], S2[1,])
Unit: microseconds
    expr      min       lq       mean    median        uq      max neval
 S1[1, ]   15.225   16.417   28.15698   17.7655   42.9905   45.692   100
 S2[1, ] 1652.362 1670.507 1771.51695 1774.1180 1787.0410 5241.863   100
Run Code Online (Sandbox Code Playgroud)

为什么速度存在差异?有没有办法加快Matrix包中的提取速度?

Ben*_*ker 5

我不知道到底是什么问题,可能是 S4 调度(这可能是像这样的小调用的很大一部分)。matrix通过(1)切换到行主格式和(2)编写我自己的专用访问器函数,我能够获得相当于(这有一个非常简单的工作,索引+访问连续的内存块)的性能。我不知道你到底想做什么,也不知道是否值得这么麻烦......

\n\n

设置示例:

\n\n
set.seed(101)\nS1 <- matrix(1*(runif(2000^2)<0.1), 2000, 2000)\n
Run Code Online (Sandbox Code Playgroud)\n\n

转换为列优先 ( dgCMatrix) 和行优先 ( dgRMatrix) 形式:

\n\n
library(Matrix)\nS2C <- Matrix(S1, sparse = TRUE)\nS2R <- as(S1,"dgRMatrix")\n
Run Code Online (Sandbox Code Playgroud)\n\n

自定义访问器:

\n\n
my_row_extract <- function(m,i=1) {\n    r <- numeric(ncol(m))   ## set up zero vector for results\n    ## suggested by @OttToomet, handles empty rows\n    inds <- seq(from=m@p[i]+1, \n                to=m@p[i+1], length.out=max(0, m@p[i+1] - m@p[i]))\n    r[m@j[inds]+1] <- m@x[inds]     ## set values\n    return(r)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

检查方法之间结果的相等性(全部TRUE):

\n\n
all.equal(S2C[1,],S1[1,])\nall.equal(S2C[1,],S2R[1,])\nall.equal(my_row_extract(S2R,1),S2R[1,])\nall.equal(my_row_extract(S2R,17),S2R[17,])\n
Run Code Online (Sandbox Code Playgroud)\n\n

基准:

\n\n
benchmark(S1[1,], S2C[1,], S2R[1,], my_row_extract(S2R,1),\n          columns=c("test","elapsed","relative"))\n##                     test elapsed relative\n## 4 my_row_extract(S2R, 1)   0.015    1.154\n## 1                S1[1, ]   0.013    1.000\n## 2               S2C[1, ]   0.563   43.308\n## 3               S2R[1, ]   4.113  316.385\n
Run Code Online (Sandbox Code Playgroud)\n\n

专用提取器与基础基质具有竞争力。S2R即使对于行提取也非常慢(令人惊讶);然而,?"dgRMatrix-class"确实说

\n\n
\n

注意:面向列的稀疏类,例如\xe2\x80\x98dgCMatrix\xe2\x80\x99,是首选,并且在\xe2\x80\x98Matrix\xe2\x80\x99 包中得到更好的支持。

\n
\n

  • 仅当行 _i_ 不为空时,该函数才能正常工作。如果你想处理空行,请使用`inds &lt;- seq(from=m@p[i]+1, to=m@p[i+1], length.out=max(0, @p[i]) +1] - m@p[i]))` 第三行。 (3认同)