Java中稀疏矩阵行的有效修改
我需要“规范化”一个大的稀疏矩阵,以便每行中的条目之和为1。对于具有一些非零项的行,每个项都除以行和。对于全为零的行,每个条目将替换为1/numberOfColumns(使矩阵的稀疏性大大降低) 如果有关系的话,我的矩阵是正方形的,对称的。我首先使用的是一个“小”测试样本,我的矩阵大小约为32K x 32K,但我们最终需要它来处理更大的矩阵。时间和内存效率都很重要(内存比时间更重要)。在标准化之前,大约1%的条目是非零的Java中稀疏矩阵行的有效修改,java,matrix,sparse-matrix,performance,memory-efficient,Java,Matrix,Sparse Matrix,Performance,Memory Efficient,我需要“规范化”一个大的稀疏矩阵,以便每行中的条目之和为1。对于具有一些非零项的行,每个项都除以行和。对于全为零的行,每个条目将替换为1/numberOfColumns(使矩阵的稀疏性大大降低) 如果有关系的话,我的矩阵是正方形的,对称的。我首先使用的是一个“小”测试样本,我的矩阵大小约为32K x 32K,但我们最终需要它来处理更大的矩阵。时间和内存效率都很重要(内存比时间更重要)。在标准化之前,大约1%的条目是非零的 规范化n x n矩阵后,需要将其乘以一系列n x k密集矩阵,其中k是一个
规范化n x n矩阵后,需要将其乘以一系列n x k密集矩阵,其中k是一个小数字(我是la4j库的作者。我确实看到您的代码中有几个地方需要改进。以下是我的建议: 调用
getRow
(以及setRow
)总是一个坏主意(特别是对于稀疏矩阵),因为它会启动矩阵行的完整复制。我建议您避免此类调用。因此,w/ogetRow
/setRow
代码应该如下所示:
SparseMatrix t = new CRSMatrix(n, n);
double uniformWeight = (double) 1 / n; // used when the rowSum is zero
for (int i = 0; i < n; i++) {
double rowSum = t.foldRow(i, Matrices.asSumAccumulator(0.0));
if (rowSum > 0.0) {
MatrixFunction divider = Matrices.asDivFunction(rowSum);
for (int j = 0; j < n; j++) {
// TODO: I should probably think about `updateRow` method
// in order to avoid this loop
t.update(i, j, divider);
}
} else {
for (int j = 0; j < n; j++) {
t.set(i, j, uniformWeight);
}
}
}
SparseMatrix t=新的crs矩阵(n,n);
double uniformWeight=(double)1/n;//行和为零时使用
对于(int i=0;i0.0){
MatrixFunction除法器=矩阵.asDivFunction(行和);
对于(int j=0;j
请试试这个。我没有编译它,但它应该可以工作
更新
使用布尔数组来跟踪相同的行是一个非常好的主意。这里的主要瓶颈是循环:
for (int j = 0; j < n; j++) {
t.set(i, j, uniformWeight);
}
for(int j=0;j
在这里,我们完全破坏了稀疏矩阵的性能/占用空间,因为将整行分配给了相同的值。因此,我要说的是,将这两个想法结合在一起:避免getRow/setRow
+带标志的额外数组(我将使用位集,它在占用空间方面非常有效)应该给你一个很棒的表演
感谢您使用la4j库,请向邮件列表或GitHub页面报告任何性能/功能问题。此处提供了所有参考资料:。如果您不使用la4j,该软件包(我维护)有一些工具可以非常高效地执行这类操作。这是可能的,因为有两个功能:
- 数据的稀疏存储
- 轻量级可变“视图”,因此您可以将矩阵的行作为向量进行适当的变换
- 创建
以将矩阵存储为稀疏向量行的集合VectorMatrixMN
- 对每一行使用
,这对于大多数零数据来说是一种有效的格式SparseIndexedVector
VectorMatrixMN m = ....
for (int i=0; i<SIZE; i++) {
AVector row=m.getRow(i);
double sum=row.elementSum();
if (sum>0) {
row.divide(sum);
} else {
m.setRow(i, new RepeatedElementVector(SIZE,1.0/SIZE));
}
}
VectorMatrixMN m=。。。。
对于(int i=0;i0){
行。除(和);
}否则{
m、 setRow(i,新的RepeatedElementVector(大小,1.0/大小));
}
}
请注意,这段代码在适当的位置修改行,因此不需要像“setRow”这样的操作就可以将数据返回到矩阵中
使用32000 x 32000稀疏矩阵和每行100个非零值的密度的这种配置,我将其计时在不到32ms的时间,以使用此代码对整个矩阵进行归一化(即,每个非零元素大约10ns==每个矩阵元素0.03ns:因此,利用稀疏性显然可以获得很大的好处)
您还可以选择对全为零的行使用ZeroVector
(这会更快,但会施加一些额外的约束,因为ZeroVectors是不可变的……)
编辑:
我编写了一个完整的示例,演示了如何将稀疏矩阵用于与此问题非常类似的用例:
row.assign(uniformWeight);row.setRow(I,row);
使用row.setRow(uniformRow)
whereuniformRow
是根据n
预先构建的。感谢您的回复和帮助!我要到下周才有机会玩这个游戏,但我非常感谢您的建议,一个一个地更新单个单元格,而不是使用setRow
和foldRow
方法来进行行的更新嗯,我确实实施了我的方案
for (int j = 0; j < n; j++) {
t.set(i, j, uniformWeight);
}
VectorMatrixMN m = ....
for (int i=0; i<SIZE; i++) {
AVector row=m.getRow(i);
double sum=row.elementSum();
if (sum>0) {
row.divide(sum);
} else {
m.setRow(i, new RepeatedElementVector(SIZE,1.0/SIZE));
}
}