【问题标题】:Creating sparse matrix from a list of sparse vectors从稀疏向量列表创建稀疏矩阵
【发布时间】:2012-01-12 23:09:02
【问题描述】:

我有一个稀疏向量列表(在 R 中)。我需要将此列表转换为稀疏矩阵。 通过 for 循环执行此操作需要很长时间。

sm<-spMatrix(length(tc2),n.col)
for(i in 1:length(tc2)){
    sm[i,]<-(tc2[i])[[1]];  
}

有没有更好的办法?

【问题讨论】:

  • 我可以回答,但需要更多指导。这些向量是否以任何稀疏格式存储?例如。您是将tc2[[1]] 存储为具有很多0 的数字向量,还是使用稀疏矩阵来表示每个向量?你能举一个数据的例子吗?
  • @DAF -- 我的回答是否解决了您的问题?如果是这样,您可以通过单击其左侧的复选标记来接受它。如果没有,您能否添加一个您想要在稀疏矩阵中组合的稀疏向量类型的示例?干杯。
  • @iterator - 我可以退后一步,从“itemset”列表开始,即每个条目都是数字列表,表示行中出现的项目/单词。我想要这个数据的稀疏矩阵表示。 Josh 的解决方案适用于小示例,但在具有 10K 行和 10k 项的示例上,我的内存不足(16 G)
  • @DAF -- 如果我有这些数据,我可能会将其设置为sparseMatrix() 构造函数的输入。您将需要三个向量(可能组织为数据框的列),它们表示每个条目的行索引、列索引和值。运行这个玩具示例,看看它是如何工作的,然后告诉我这是怎么回事:sparseMatrix(i=1:4, j=4:1, x=c(2,4,5,9))。祝你好运!
  • @Josh - 谢谢!这似乎是最有效的解决方案。我在下面发布了一个功能。

标签: r sparse-matrix


【解决方案1】:

这是一个两步解决方案:

  • 使用lapply()as(..., "sparseMatrix")sparseVectors 列表转换为一列sparseMatrices 的列表。

  • 使用do.call()cBind()sparseMatrices 组合成一个sparseMatrix


require(Matrix)

# Create a list of sparseVectors
ss <- as(c(0,0,3, 3.2, 0,0,0,-3), "sparseVector")
l <- replicate(3, ss)

# Combine the sparseVectors into a single sparseMatrix
l <- lapply(l, as, "sparseMatrix")
do.call(cBind, l)

# 8 x 3 sparse Matrix of class "dgCMatrix"
#                    
# [1,]  .    .    .  
# [2,]  .    .    .  
# [3,]  3.0  3.0  3.0
# [4,]  3.2  3.2  3.2
# [5,]  .    .    .  
# [6,]  .    .    .  
# [7,]  .    .    .  
# [8,] -3.0 -3.0 -3.0

【讨论】:

  • 谢谢!这适用于示例并执行我想要的操作(除了我在 do.call 中使用 rBind ,因为我在列表中有行)。但是,在文本数据(10K 行和最多 10K 特征,虽然非常稀疏)上,do.call 将 R 挂起很长时间,所以我最终杀死了它。有什么建议吗?
  • 不知道为什么运行缓慢。看起来rBind 实际上可能会递归调用rbind2(一次将两行绑定在一起)。这 变得非常慢,大量的向量要 rbind 在一起。但是,由于我已经建议了一种替代方法来构建您真正想要的矩阵,因此我将暂缓对此进行进一步调查。干杯。
【解决方案2】:

这个场景,cbind 处理一堆向量,非常适合将信息直接转储到 sparse, column-oriented 矩阵(dgCMatrix 类)中。

这是一个可以做到这一点的函数:

sv.cbind <- function (...) {
    input <- lapply( list(...), as, "dsparseVector" )
    thelength <- unique(sapply(input,length))
    stopifnot( length(thelength)==1 )
    return( sparseMatrix( 
            x=unlist(lapply(input,slot,"x")), 
            i=unlist(lapply(input,slot,"i")), 
            p=c(0,cumsum(sapply(input,function(x){length(x@x)}))),
            dims=c(thelength,length(input))
        ) )
}

通过快速测试,这看起来比强制 + cBind 快 10 倍左右:

require(microbenchmark)
xx <- lapply( 1:10, function (k) {
            sparseVector( x=rep(1,100), i=sample.int(1e4,100), length=1e4 )
        } )
microbenchmark( do.call( sv.cbind, xx ), do.call( cBind, lapply(xx,as,"sparseMatrix") ) )
# Unit: milliseconds
#                                            expr       min        lq      mean   median       uq       max neval cld
#                           do.call(sv.cbind, xx)  1.398565  1.464517  1.540172  1.49487  1.55911  3.455421   100  a 
#  do.call(cBind, lapply(xx, as, "sparseMatrix")) 16.037890 16.356268 16.956326 16.59854 17.49956 20.256253   100   b

【讨论】:

  • cbind 最终调用了 S4 方法。见here。因此,this code 将被调用,并且可能会有您不执行的检查。我不确定这是否重要,但可能。
  • @petrelharp。出色的,最直观的快速操作解决方案。我不想做的所有编码都做得很好。
【解决方案3】:

感谢 Josh O'Brien 提出的解决方案:创建 3 个列表,然后创建 sparseMatrix。 我在此处包含此代码:

vectorList2Matrix<-function(vectorList){
 nzCount<-lapply(vectorList, function(x) length(x@j));
 nz<-sum(do.call(rbind,nzCount));
 r<-vector(mode="integer",length=nz);
 c<-vector(mode="integer",length=nz);
 v<-vector(mode="integer",length=nz);
 ind<-1;
 for(i in 1:length(vectorList)){
    ln<-length(vectorList[[i]]@i);
    if(ln>0){
     r[ind:(ind+ln-1)]<-i;
     c[ind:(ind+ln-1)]<-vectorList[[i]]@j+1
     v[ind:(ind+ln-1)]<-vectorList[[i]]@x
     ind<-ind+ln;
    }
 }
 return (sparseMatrix(i=r,j=c,x=v));
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2017-03-31
  • 1970-01-01
  • 2012-01-10
  • 2017-03-26
  • 2016-07-29
  • 1970-01-01
  • 2021-12-05
  • 2018-01-19
相关资源
最近更新 更多