【问题标题】:In Julia, How can I column-normalize a sparse matrix?在 Julia 中,如何对稀疏矩阵进行列归一化?
【发布时间】:2014-08-09 09:59:33
【问题描述】:

如果我使用 sparse(i, j, k) 构造函数构造了一个稀疏矩阵,那么我该如何规范化矩阵的列(以便每列总和为 1)?在创建矩阵之前,我无法有效地规范化条目,因此感谢您的帮助。谢谢!

【问题讨论】:

    标签: matrix normalization sparse-matrix julia


    【解决方案1】:

    以下给出了您想要的: A = sprand(4,5,0.5) B = A./sparse(sum(A,1))

    问题在于 sum(A,1) 给出了一个 1x5 密集数组,因此通过 ./ 运算符与稀疏矩阵 A 组合得到一个密集数组。所以你需要强制它是稀疏类型的。或者你可以输入 稀疏(A ./ sum(A,1))。

    【讨论】:

      【解决方案2】:
      # get the column sums of A
      S = vec(sum(A,1))
      
      # get the nonzero entries in A. ei is row index, ej is col index, ev is the value in A
      ei,ej,ev = findnz(A)
      
      # get the number or rows and columns in A
      m,n = size(A)
      
      # create a new normalized matrix. For each nonzero index (ei,ej), its new value will be
      # the old value divided by the sum of that column, which can be obtained by S[ej]
      A_normalized = sparse(ei,ej,ev./S[ej],m,n)
      

      【讨论】:

      • 为了将来参考,在你的答案后面给出一些解释是一件好事。在这种情况下,我不明白 ei,ej,ev 的用途是什么——它们是 bi.bj.bv 吗?
      【解决方案3】:

      请记住,Julia 中的稀疏矩阵是压缩列形式。所以你可以直接访问数据:

      for col = 1 : size(A, 2)
        i = A.colptr[col]
        k = A.colptr[col+1] - 1
        n = i <= k ? norm(A.nzval[i:k]) : 0.0  # or whatever you like
        n > 0.0 && (A.nzval[i:k] ./= n)
      end
      

      【讨论】:

        【解决方案4】:

        给定一个矩阵 A(不管它是否稀疏)按任意维度归一化

         A ./ sum(A,1) or  A ./ sum(A,2)
        

        证明它有效:

        A = sprand(10,10,0.3)   
        println(sum(A,1))
        println(A ./ sum(A,1))
        

        只有警告

        A[1,:] = 0
        println(A ./ sum(A,1))
        

        如您所见,第 1 列现在只包含 NaN,因为我们除以零。此外,我们最终得到一个矩阵而不是稀疏矩阵。

        另一方面,您可以快速为您的问题找到有效的专业解决方案。

        function normalize_columns(A :: SparseMatrixCSC)
                  sums = sum(A,1)
                  I,J,V = findnz(A)
                  for idx in 1:length(V)
                    V[idx] /= sums[J[idx]]
                  end
                  sparse(I,J,V)
        end
        

        @Matt B 在我打字的时候得到了一个非常相似的答案:)

        【讨论】:

          【解决方案5】:

          最简单的方法是通过列的总和进行广播划分:

          julia> A = sprand(4,5,.5)
                 A./sum(A,1)
          4x5 Array{Float64,2}:
           0.0        0.0989976  0.0        0.0       0.0795486
           0.420754   0.458653   0.0986313  0.0       0.0
           0.0785525  0.442349   0.0        0.856136  0.920451
           0.500693   0.0        0.901369   0.143864  0.0
          

          ……但它看起来还没有针对稀疏矩阵进行优化,并且回退到一个完整的矩阵。所以一个简单的循环遍历列就可以了:

          julia> for (col,s) in enumerate(sum(A,1))
                   s == 0 && continue # What does a "normalized" column with a sum of zero look like?
                   A[:,col] = A[:,col]/s
                 end
                 A
          4x5 sparse matrix with 12 Float64 entries:
              [2, 1]  =  0.420754
              [3, 1]  =  0.0785525
              [4, 1]  =  0.500693
              [1, 2]  =  0.0989976
              [2, 2]  =  0.458653
              [3, 2]  =  0.442349
              [2, 3]  =  0.0986313
              [4, 3]  =  0.901369
              [3, 4]  =  0.856136
              [4, 4]  =  0.143864
              [1, 5]  =  0.0795486
              [3, 5]  =  0.920451
          
          julia> sum(A,1)
          1x5 Array{Float64,2}:
           1.0  1.0  1.0  1.0  1.0
          

          这完全在稀疏矩阵中工作并且就地完成(尽管它仍然为每个列切片分配新的稀疏矩阵)。

          【讨论】:

            猜你喜欢
            • 2018-05-21
            • 1970-01-01
            • 1970-01-01
            • 2017-10-03
            • 2018-06-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-03-12
            相关资源
            最近更新 更多