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

R 与常规矩阵类相比,矩阵包中的提取速度非常慢,r,performance,matrix,sparse-matrix,R,Performance,Matrix,Sparse Matrix,这是一个使用与常规R类比较稀疏和密集的大型矩阵行提取的示例 对于密集矩阵,基类矩阵的速度几乎快395倍: 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 ex

这是一个使用与常规
R
类比较稀疏和密集的大型矩阵行提取的示例

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

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

为什么会出现速度差异?有没有办法加快软件包中的提取速度?

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

树立榜样:

set.seed(101)
S1 <- matrix(1*(runif(2000^2)<0.1), 2000, 2000)
自定义访问器:

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

benchmark(S1[1,], S2C[1,], S2R[1,], my_row_extract(S2R,1),
          columns=c("test","elapsed","relative"))
##                     test elapsed relative
## 4 my_row_extract(S2R, 1)   0.015    1.154
## 1                S1[1, ]   0.013    1.000
## 2               S2C[1, ]   0.563   43.308
## 3               S2R[1, ]   4.113  316.385
专用提取器与基矩阵具有竞争性
S2R
速度非常慢,即使对于行提取也是如此(令人惊讶);但是,
?“dgRMatrix类”
确实说

注意:“矩阵”软件包中首选并更好地支持面向列的稀疏类,例如“dgCMatrix”


只有当行i不为空时,该函数才能正常工作。如果要处理空行,请使用类似于
inds的方法
my_row_extract <- function(m,i=1) {
    r <- numeric(ncol(m))   ## set up zero vector for results
    ## suggested by @OttToomet, handles empty rows
    inds <- seq(from=m@p[i]+1, 
                to=m@p[i+1], length.out=max(0, m@p[i+1] - m@p[i]))
    r[m@j[inds]+1] <- m@x[inds]     ## set values
    return(r)
}
all.equal(S2C[1,],S1[1,])
all.equal(S2C[1,],S2R[1,])
all.equal(my_row_extract(S2R,1),S2R[1,])
all.equal(my_row_extract(S2R,17),S2R[17,])
benchmark(S1[1,], S2C[1,], S2R[1,], my_row_extract(S2R,1),
          columns=c("test","elapsed","relative"))
##                     test elapsed relative
## 4 my_row_extract(S2R, 1)   0.015    1.154
## 1                S1[1, ]   0.013    1.000
## 2               S2C[1, ]   0.563   43.308
## 3               S2R[1, ]   4.113  316.385