我有一个300万x 900万稀疏矩阵,有数十亿个非零项。 R和Python不允许稀疏矩阵具有超过MAXINT非零的条目,因此我发现自己使用Julia。
虽然使用标准偏差来缩放这些数据是微不足道的,但是贬低当然是一种天真的方式,因为它会产生一个密集的,超过200 TB的矩阵。
找到执行svd的相关代码julia从我的阅读中,这段代码的一个关键元素是AtA_or_AAt结构和围绕它们的几个函数,特别是A_mul_B!。为方便起见,下面复制
struct AtA_or_AAt{T,S} <: AbstractArray{T, 2}
A::S
buffer::Vector{T}
end
function AtA_or_AAt(A::AbstractMatrix{T}) where T
Tnew = typeof(zero(T)/sqrt(one(T)))
Anew = convert(AbstractMatrix{Tnew}, A)
AtA_or_AAt{Tnew,typeof(Anew)}(Anew, Vector{Tnew}(max(size(A)...)))
end
function A_mul_B!(y::StridedVector{T}, A::AtA_or_AAt{T}, x::StridedVector{T}) where T
if size(A.A, 1) >= size(A.A, 2)
A_mul_B!(A.buffer, A.A, x)
return Ac_mul_B!(y, A.A, A.buffer)
else
Ac_mul_B!(A.buffer, A.A, x)
return A_mul_B!(y, A.A, A.buffer)
end
end
size(A::AtA_or_AAt) = ntuple(i -> min(size(A.A)...), Val(2))
ishermitian(s::AtA_or_AAt) = true
这被传递到eigs函数中,在那里发生了一些魔法,然后输出被处理到SVD的相关组件。
我认为最好的方法是让这项工作以“飞行中心”为中心。类型设置是使用AtA_or_AAT_centered版本来执行子类AtA_or_AAT,或多或少地模仿行为,但也存储列均值,并重新定义A_mul_B!功能恰当。
但是,我并没有非常使用朱莉娅,并且已经遇到了一些难以修改的问题。在我再次尝试深入研究之前,我想知道如果这被认为是一个合适的攻击计划,或者如果在这样一个大矩阵上进行SVD的简单方法,我是否能得到反馈(我还没有#39)看到它,但我可能错过了一些东西。)
编辑:我没有修改基础Julia,而是尝试编写一个"Centered Sparse Matrix"包来保持输入稀疏矩阵的稀疏结构,但是在各种计算中适当地进入列意味着。它实施的内容有限,而且有效。不幸的是,它仍然太慢,尽管为了优化事物做了一些非常广泛的努力。
答案 0 :(得分:3)
在对稀疏矩阵算法进行了大量研究之后,我意识到在减法上分配乘法效率要高得多:
如果我们的居中矩阵Ac
由原始n
x m
矩阵A
组成,其列向量意为M
,其中n
1}} x 1
向量,我将称之为1
。我们乘以m
x k
矩阵X
Ac := (A - 1M')
AcX = X
= AX - 1M'X
我们基本上完成了。实际上,这非常简单。
AX
可以使用通常的稀疏矩阵乘法函数执行,M'X
是一个密集的向量矩阵内积,而1的“广播”向量(使用Julia的术语)来执行AX
中间结果的每一行。大多数语言都有一种方法可以进行广播,而无需实现额外的内存分配。
这是我在package为AcX和Ac'X实施的内容。然后可以将生成的对象传递给算法,例如svds
函数,该函数仅依赖于矩阵乘法和转置乘法。