是否有一种简单有效的方法可以使稀疏的scipy矩阵(例如lil_matrix或csr_matrix)对称?
当填充大的稀疏共生矩阵时,同时填充[row,col]和[col,row]将非常低效。我想做的是:
for i in data:
for j in data:
if cond(i, j):
lil_sparse_matrix[i, j] = some_value
# want to avoid this:
# lil_sparse_matrix[j, i] = some_value
# this is what I'm looking for:
lil_sparse.make_symmetric()
这类似于stackoverflow's numpy-smart-symmetric-matrix question,但特别适用于scipy稀疏矩阵。
答案 0 :(得分:3)
好的,它会使作业语句的数量增加一倍,但从大局来看,这会带来多少惩罚呢?
lil
是索引作业的最有效格式,但我已经在其他帖子中进行了探讨。如果我没记错的话,直接分配到data
的{{1}}和rows
属性的速度会更快,但在一次填充整行时这些属性主要是有价值的。
lil
也相对较快,但我发现分配到常规字典,然后更新dok
的速度更快。 (A dok
是一个字典子类。)
但如果您转到dok
路线 - 构建coo
,data
和rows
值列表,则同时创建cols
和i,j
一次性的条款并不昂贵。如果你可以一次定义一堆值,而不是迭代所有j,i
,那就更好了。
如此有效地创建对称矩阵只是有效矩阵定义问题的一个子集。
我不知道稀疏包中的任何对称化函数。我想知道线性代数函数是否具有对称条件。我怀疑最有效的处理程序只是假设矩阵是上三角或下三角,没有明确的对称值。
您可以创建上三个矩阵,然后将值复制到下面。在密集的情况下,最简单的方法是对矩阵及其转置求和(并可能减去对角线)。但是稀疏矩阵求和在某种程度上是有效的,因此可能不是最好的。但我还没有做过任何测试。
============
至少转置的总和并没有给我任何效率警告:
i,j
转置之和(减去重复的对角线):
In [383]: M=sparse.lil_matrix((10,10),dtype=int)
In [384]:
In [384]: for i in range(10):
...: for j in range(i,10):
...: v=np.random.randint(0,10)
...: if v>5:
...: M[i,j]=v
...:
In [385]: M
Out[385]:
<10x10 sparse matrix of type '<class 'numpy.int32'>'
with 22 stored elements in LInked List format>
In [386]: M.A
Out[386]:
array([[0, 7, 7, 0, 9, 0, 7, 0, 0, 9],
[0, 0, 7, 8, 0, 8, 0, 0, 9, 0],
[0, 0, 0, 7, 0, 0, 9, 0, 8, 0],
[0, 0, 0, 0, 0, 0, 6, 0, 6, 6],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 8, 9, 0, 8],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 8, 8],
[0, 0, 0, 0, 0, 0, 0, 0, 6, 8],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
双重分配方法:
In [389]: M+M.T-sparse.diags(M.diagonal(),dtype=int)
Out[389]:
<10x10 sparse matrix of type '<class 'numpy.int32'>'
with 43 stored elements in Compressed Sparse Row format>
In [390]: _.A
Out[390]:
array([[0, 7, 7, 0, 9, 0, 7, 0, 0, 9],
[7, 0, 7, 8, 0, 8, 0, 0, 9, 0],
[7, 7, 0, 7, 0, 0, 9, 0, 8, 0],
[0, 8, 7, 0, 0, 0, 6, 0, 6, 6],
[9, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 8, 0, 0, 0, 0, 8, 9, 0, 8],
[7, 0, 9, 6, 0, 8, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 9, 0, 0, 8, 8],
[0, 9, 8, 6, 0, 0, 0, 8, 6, 8],
[9, 0, 0, 6, 0, 8, 0, 8, 8, 0]], dtype=int32)
我还没有做任何时间。
In [391]: M=sparse.lil_matrix((10,10),dtype=int)
In [392]: for i in range(10):
...: for j in range(i,10):
...: v=np.random.randint(0,10)
...: if v>5:
...: M[i,j]=v
...: M[j,i]=v
方法:
coo
===============
制作上三角矩阵可能会快一点,并且随着列表(或数组)串联扩展到更低
In [398]: data,rows,cols=[],[],[]
In [399]: for i in range(10):
...: for j in range(i,10):
...: v=np.random.randint(0,10)
...: if v>5:
...: if i==j:
...: # prevent diagonal duplication
...: data.append(v)
...: rows.append(i)
...: cols.append(j)
...: else:
...: data.extend((v,v))
...: rows.extend((i,j))
...: cols.extend((j,i))
...:
In [400]: sparse.coo_matrix((data,(rows,cols)),shape=(10,10)).A
Out[400]:
array([[0, 8, 0, 6, 8, 9, 9, 0, 0, 0],
[8, 7, 0, 0, 0, 6, 0, 8, 0, 0],
[0, 0, 0, 0, 0, 0, 9, 9, 7, 9],
[6, 0, 0, 0, 7, 0, 0, 0, 0, 6],
[8, 0, 0, 7, 0, 0, 8, 0, 0, 0],
[9, 6, 0, 0, 0, 0, 6, 0, 0, 0],
[9, 0, 9, 0, 8, 6, 8, 0, 0, 0],
[0, 8, 9, 0, 0, 0, 0, 6, 0, 6],
[0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 9, 6, 0, 0, 0, 6, 0, 9]])
这复制了对角线,我需要以一种方式或其他方式解决(重复的铜指数相加)。但它给出了如何将In [401]: data,rows,cols=[],[],[]
In [402]: for i in range(10):
...: for j in range(i,10):
...: v=np.random.randint(0,10)
...: if v>5:
...: data.append(v)
...: rows.append(i)
...: cols.append(j)
In [408]: sparse.coo_matrix((data,(rows,cols)),shape=(10,10)).A
Out[408]:
array([[8, 0, 0, 9, 8, 7, 0, 7, 9, 0],
[0, 7, 6, 0, 0, 7, 0, 0, 9, 0],
[0, 0, 9, 8, 0, 9, 6, 0, 0, 6],
...]])
In [409]: data1=data+data
In [410]: rows1=rows+cols
In [411]: cols1=cols+rows
In [412]: sparse.coo_matrix((data1,(rows1,cols1)),shape=(10,10)).A
样式输入收集到更大的块中的想法。
答案 1 :(得分:3)
是的,肯定有一种更有效,更简单的方法。 如果要创建矩阵,hpaulj的答案应该起作用,但是如果已经有矩阵,则可以执行以下操作:
rows, cols = sparse_matrix.nonzero()
sparse_matrix[cols, rows] = sparse_matrix[rows, cols]
这应该适用于除coo_matrix以外的所有类型scipy的稀疏矩阵。
编辑:注明为coo_matrix。