【问题标题】:R - Update Columns in Very Large Sparse MatrixR - 更新非常大的稀疏矩阵中的列
【发布时间】:2018-02-09 19:12:30
【问题描述】:

我需要更新稀疏矩阵中的某些列,但该操作需要非常长的时间才能完成。

我有一个稀疏矩阵,行数少于 3M,列数约为 1500。我也有一个行数相同的数据框,但只有 10 列。我想用 data.frame 中的值更新矩阵中的某些列索引。

我对普通矩阵执行此操作没有问题,但在尝试使用稀疏矩阵时,即使是单列也需要 eons。

以下是我正在使用的代码,需要进行哪些更改才能使其高效运行?

library(Matrix)

x <- Matrix(0, nrow = 2678748, ncol = 1559, sparse = TRUE)
df <- data.frame(replicate(5,sample(0:1,2678748,rep = TRUE)))

var_nums <- sample(1:1559,size = 5)

for (i in 1:5){
  x[,var_nums[i]] <- df[,i]
}

【问题讨论】:

    标签: r matrix sparse-matrix


    【解决方案1】:

    使用Matrix::cBind 函数并消除for 循环,我能够在1 秒内完成。

    library(Matrix)
    
    x  <- Matrix(0, nrow = 2678748, ncol = 1559, sparse = TRUE)
    df <- data.frame(replicate(5,sample(0:1,2678748,rep = TRUE)))
    
    var_nums <- sample(1:1559,size = 5)
    
    t <- Sys.time()
    x            <- x[,-var_nums]
    x            <- Matrix::cBind(x, Matrix::as.matrix(df))
    Sys.time()-t
    
    Time difference of 0.541054 secs
    

    订单已保留(还不到 1 秒!)

    library(Matrix)
    
    x  <- Matrix(0, nrow = 2678748, ncol = 1559, sparse = TRUE)
    df <- data.frame(replicate(5,sample(0:1,2678748,rep = TRUE)))
    
    colnames(x) <- paste("col", 1:ncol(x))
    col.order   <- colnames(x)
    
    cols <- sample(colnames(x),size = 5)
    colnames(df) <- cols
    
    t <- Sys.time()
    x            <- x[,-which(colnames(x) %in% cols)]
    x            <- Matrix::cBind(x, Matrix::as.matrix(df) )
    x            <- x[,col.order]
    Sys.time()-t
    >     Time difference of 0.550012 secs
    
    # Proof that order is preserved:
    identical(colnames(x), col.order)
    

    是的

    【讨论】:

      【解决方案2】:

      你可以使用sparseMatrixijx表示法

      library(Matrix)
      
      # data
      set.seed(1)
      # Changed the dim size to fit in my laptop memory
      nc=10
      nr=100
      n=5
      
      df <- data.frame(replicate(n,sample(0:1,nr,rep = TRUE))) 
      var_nums <- sample(1:nc,size = n)
      
      #Yours    
      x <- Matrix(0, nrow = nr, ncol = nc, sparse = TRUE)
      for (i in 1:n){
        x[,var_nums[i]] <- df[,i]
      }
      
      # new version
      i = ((which(df==1)-1) %% nr) +1
      j = rep(var_nums, times=colSums(df))
      y = sparseMatrix(i=i, j=j, x=1, dims=c(nrow(df), nc))
      
      all.equal(x, y, check.attributes=FALSE)
      

      比较速度

      f1 <- function(){     
          for (i in 1:n){
            x[,var_nums[i]] <- df[,i]
          }
          x
      }
      
      f2 <- function(){
          i = ((which(df==1)-1) %% nr) +1  
          j = rep(var_nums, times=colSums(df))
          y = sparseMatrix(i=i, j=j, x=1, dims=c(nrow(df), nc))
          y
      }
      
      microbenchmark::microbenchmark(f1(), f2())
      
      Unit: milliseconds
       expr      min       lq     mean   median       uq       max neval cld
       f1() 4.594229 4.694205 5.010071 4.770475 4.891649 12.666554   100   b
       f2() 1.274745 1.298663 1.464237 1.329534 1.392146  7.153076   100  a 
      

      尝试更大的

      nc=100
      nr=10000
      n=50
      set.seed(1)
      df <- data.frame(replicate(n,sample(0:1,nr,rep = TRUE)))
      var_nums <- sample(1:nc,size = n)
      x <- Matrix(0, nrow = nr, ncol = nc, sparse = TRUE)
      
      all.equal(f1(), f2(), check.attributes=FALSE)
      
      microbenchmark::microbenchmark(f1(), f2(), times=1)
      Unit: milliseconds
       expr         min          lq        mean      median          uq         max neval
       f1() 21605.60251 21605.60251 21605.60251 21605.60251 21605.60251 21605.60251     1
       f2()    60.87275    60.87275    60.87275    60.87275    60.87275    60.87275     1
      

      【讨论】:

        【解决方案3】:

        这有点麻烦,但是你可以像这样将需要的列绑定在一起

        Nc = NCOL(x)
        
          Matrix(cbind(
          x[, 1:(var_nums[1]-1)], 
          df[, 1],
          x[, (var_nums[1]+1):(var_nums[2]-1)],
          df[, 2],
          x[, (var_nums[2]+1):(var_nums[3]-1)],
          df[, 3],
          x[, (var_nums[3]+1):(var_nums[4]-1)],
          df[, 4],
          x[, (var_nums[4]+1):(var_nums[5]-1)],
          df[, 5],
          x[, (var_nums[5]+1):Nc]),
          sparse = TRUE)
        

        当 df 只有 5 列要插入时,这还不错。如果 df 有更多或不同数量的列,那么不同的语法可能更合适。无论如何,绑定列是比较快的。

        【讨论】:

          猜你喜欢
          • 2017-01-10
          • 2023-03-05
          • 2018-05-12
          • 2011-03-11
          • 2016-11-22
          • 1970-01-01
          • 1970-01-01
          • 2019-07-09
          • 2012-05-29
          相关资源
          最近更新 更多