【问题标题】:Extraction speed in Matrix package is very slow compared to regular matrix class与常规矩阵类相比,Matrix 包中的提取速度非常慢
【发布时间】:2018-06-08 09:27:26
【问题描述】:

这是一个比较使用Matrix package 与常规R base-matrix 类从稀疏和密集矩阵中提取行的示例。

对于稠密矩阵,基类 matrix 的速度几乎快 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

对于稀疏矩阵,再次支持matrix 几乎是 63 倍。

## 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

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

【问题讨论】:

    标签: r performance matrix sparse-matrix


    【解决方案1】:

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

    设置示例:

    set.seed(101)
    S1 <- matrix(1*(runif(2000^2)<0.1), 2000, 2000)
    

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

    library(Matrix)
    S2C <- Matrix(S1, sparse = TRUE)
    S2R <- as(S1,"dgRMatrix")
    

    自定义访问器:

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

    检查方法间结果的相等性(所有TRUE):

    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
    

    专用提取器与基矩阵具有竞争力。 S2R 非常慢,即使对于行提取也是如此(令人惊讶);但是,?"dgRMatrix-class" 确实说

    注意: 面向列的稀疏类,例如“dgCMatrix”,在“Matrix”包中是首选和更好的支持。

    【讨论】:

    • 只有当行 i 不为空时,该函数才能正常工作。如果您想处理空行,请在第三行使用 inds &lt;- seq(from=m@p[i]+1, to=m@p[i+1], length.out=max(0, @p[i+1] - m@p[i])) 之类的内容。
    猜你喜欢
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多