如何有效地在(稀疏)矩阵中插入行?

How to insert row in a (sparse) matrix efficiently?

我有一个巨大的稀疏矩阵,需要在特定的行索引处插入一行。我基本上应用了建议的技术 here,但效率非常低,因为它复制了原始矩阵。

下面简单介绍一下代码,范围是高效生成M2(理想情况下,直接替换M,这样就连M2都不需要了):

library(Matrix)

M  = as(cbind(1:4,1:4),"sparseMatrix") # original sparse matrix
M # view
v  = c(2,4) # row indices where new rows should be inserted
M2 = M # copy matrix to keep sparse class
for(i in 1:length(v)) M2 = rbind(M2,rep(0, ncol(M2))) # insert new rows at end
M2[-v,] = M # get each row in v 2 times ## <- THIS takes very long
M2[v,] = 0 # populate the newly inserted rows (e.g. here: 0)
M2 # view

理想情况下,我正在寻找一个函数,例如 append 用于向量或 add_row 用于小标题。

编辑:我注意到上面的过程不仅效率低下,而且也不是我想要的,因为它在 new 的索引 2 和 4 处添加了行(结果)矩阵 M2,而我正在寻找在 old(初始)矩阵的索引 2 和 4 处添加行,即现在的最终结果是:

[1,] 1 1
[2,] . .
[3,] 2 2
[4,] . .
[5,] 3 3
[6,] 4 4

即在新矩阵的索引 2 和 4 处添加了行。我要找的是:

[1,] 1 1
[2,] . .
[3,] 2 2
[4,] 3 3
[5,] . .
[6,] 4 4

即在旧矩阵的索引 2 和 4 之前添加了新行。在他的 +1 回答中,@Ben Bolker 正确地解释了这一点。 :)

我认为这应该相当有效地工作:它以稀疏(dgCMatrixdgTMatrix)格式处理矩阵的基础行索引和维度。

add_rows <- function(M,v) {
    oldind <- seq(dim(M)[1])-1L   ## all rows (0-indexed)
    ## new row indices: count how many rows are inserted before a given row
    ## (maybe a clearer/better/more efficient way to do this?)
    newind <- oldind + as.integer(rowSums(outer(oldind,v,">=")))
    ## modify dimensions
    M@Dim <- M@Dim + c(length(v),0L)
    ## modify row indices (1L accounts for 0 vs 1-indexing)
    M@i <- newind[M@i+1L]
    M
}

最有可能成为 (memory/computation) 瓶颈的部分是新行索引的计算。我通过构建 all 行号的索引来做到这一点。下面的版本只对占用的行进行 newind 计算,代价是额外调用 unique()match().

add_rows_2 <- function(M,v) {
    oldind <- unique(M@i)
    ## new row indices
    newind <- oldind + as.integer(rowSums(outer(oldind,v,">=")))
    ## modify dimensions
    M@Dim <- M@Dim + c(length(v),0L)
    M@i <- newind[match(M@i,oldind)]
    M
}