【问题标题】:R: Way to map over all entries in a sparse matrixR:映射稀疏矩阵中所有条目的方法
【发布时间】:2012-09-29 01:13:19
【问题描述】:

我有一个从 R 的 Matrix 包创建的稀疏矩阵。我想遍历矩阵中的每个条目并执行操作,将结果保存在另一个稀疏矩阵中,该矩阵与原始矩阵具有相同的索引。

例如,假设我有稀疏矩阵 A:

1 . 1
2 . .
. . 4

ColSum 看起来像:

3 . 5

RowSum 看起来像:

2
2
4

我想遍历 A 并执行此操作

(1,1) > 3*2
(2,1) > 2*3
(1,3) > 2*5
(3,3) > 4*5

创建 B:

6 . 10
6 . .
. . 20

我将如何以矢量化方式执行此操作?

我认为函数 foo 看起来像:

B=fooMap(A,fun)

有趣的是:

fun(row,col) = RowSums(row) * ColSums(col)

什么是 fooMap?

编辑:

我选择了弗洛德尔的解决方案。它使用 summary 将稀疏矩阵转换为 i,j,x 数据帧,然后使用 with & friends 对该帧执行操作,然后将结果转换回稀疏矩阵。使用这种技术,with/within 运算符是 fooMap;只需先将稀疏矩阵转换为 i,j,x 数据帧,以便使用 with/within。

这是一个解决这个特殊问题的单线。

B = with(summary(A), sparseMatrix(i=i, j=j, x = rowSums(A)[i] * colSums(A)[j]))

【问题讨论】:

    标签: r vectorization sparse-matrix


    【解决方案1】:

    每当我对稀疏矩阵进行元素操作时,我都会在矩阵本身和它的summary 表示之间来回切换:

    summ.B <- summary(A)
    summ.B <- within(summ.B, x <- rowSums(A)[i]*colSums(A)[j])
    B <- sparseMatrix(i = summ.B$i, j = summ.B$j, x = summ.B$x)
    B
    # 3 x 3 sparse Matrix of class "dgCMatrix"
    #            
    # [1,] 6 . 10
    # [2,] 6 .  .
    # [3,] . . 20
    

    【讨论】:

    • within 看起来非常强大。因此,在内部,您可以读取对象中的所有列,由它们的框架名称引用?这用于构建原始对象的略微修改版本,但作为不共享任何相同内存的新对象,是吗?
    • 但是如果矩阵很大,这不意味着在将汇总对象分配给某个变量后它会占用双倍空间吗?
    • 确实如此。不过,暂时将内存使用量增加一倍/三倍是一项非常常见的任务,这是实现速度的必要条件。如果你的数据太大以至于占用了你一半以上的内存,你会感到痛苦......
    【解决方案2】:

    这是一种在每一步都使用稀疏矩阵的方法。

    ## Load library and create example sparse matrix
    library(Matrix)
    m <- sparseMatrix(i = c(1,2,1,3), j = c(1,1,3,3), x = c(1,2,1,4))
    
    ## Multiply each cell by its respective row and column sums.
    Diagonal(x = rowSums(m)) %*% (1*(m!=0)) %*% Diagonal(x = colSums(m))
    # 3 x 3 sparse Matrix of class "dgCMatrix"
    #            
    # [1,] 6 . 10
    # [2,] 6 .  .
    # [3,] . . 20
    

    (1*(m!=0)) 中的1* 被用来强制将m!=0 生成的类“lgCMatrix”的逻辑矩阵转换回数字矩阵类“dgCMatrix”。一个冗长(但可能更清晰)的替代方案会使用as(m!=0, "dgCMatrix") 代替它。)

    【讨论】:

    • 这个非常简洁。我当然可以将它用于映射函数运算符为 * 的情况。而这绝对是一个很常见的操作。但是我的线性代数经验并不是很好。这种方法是否可以推广到其他运算符,比如 rowSum + colSum(而不是 *)?
    • 当然你可以这样做,像这样:m2 &lt;- 1*(m!=0); (Diagonal(x=rowSums(m)) %*% m2) + (m2 %*% Diagonal(x=colSums(m)))。但是,在您对基本矩阵运算有一个合理的感觉之前,进行任意概括可能是一个挑战。
    猜你喜欢
    • 2016-10-03
    • 2011-03-30
    • 1970-01-01
    • 2011-06-24
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 2013-06-26
    相关资源
    最近更新 更多