R - 更新超大稀疏矩阵中的列

时间:2017-08-31 18:38:02

标签: r matrix sparse-matrix

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

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

使用普通矩阵执行此操作时没有问题,但在使用稀疏矩阵进行此操作时,即使只有一列也需要很长时间。

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

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

3 个答案:

答案 0 :(得分: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)
  

TRUE

答案 1 :(得分:1)

Yuo可以使用i

jxsparseMatrix表示法
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

答案 2 :(得分:0)

这有点麻烦,但您可以将所需的列绑定在一起,就像这样

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具有更多或不同数量的列,则不同的语法可能更合适。无论如何,绑定列相对较快。