【发布时间】:2014-08-09 09:59:33
【问题描述】:
如果我使用 sparse(i, j, k) 构造函数构造了一个稀疏矩阵,那么我该如何规范化矩阵的列(以便每列总和为 1)?在创建矩阵之前,我无法有效地规范化条目,因此感谢您的帮助。谢谢!
【问题讨论】:
标签: matrix normalization sparse-matrix julia
如果我使用 sparse(i, j, k) 构造函数构造了一个稀疏矩阵,那么我该如何规范化矩阵的列(以便每列总和为 1)?在创建矩阵之前,我无法有效地规范化条目,因此感谢您的帮助。谢谢!
【问题讨论】:
标签: matrix normalization sparse-matrix julia
以下给出了您想要的: A = sprand(4,5,0.5) B = A./sparse(sum(A,1))
问题在于 sum(A,1) 给出了一个 1x5 密集数组,因此通过 ./ 运算符与稀疏矩阵 A 组合得到一个密集数组。所以你需要强制它是稀疏类型的。或者你可以输入 稀疏(A ./ sum(A,1))。
【讨论】:
# 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)
【讨论】:
请记住,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
【讨论】:
给定一个矩阵 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 在我打字的时候得到了一个非常相似的答案:)
【讨论】:
最简单的方法是通过列的总和进行广播划分:
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
这完全在稀疏矩阵中工作并且就地完成(尽管它仍然为每个列切片分配新的稀疏矩阵)。
【讨论】: