scipy稀疏矩阵的对称化

时间:2016-11-06 21:08:10

标签: python numpy scipy

是否有一种简单有效的方法可以使稀疏的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稀疏矩阵。

2 个答案:

答案 0 :(得分:3)

好的,它会使作业语句的数量增加一倍,但从大局来看,这会带来多少惩罚呢?

lil是索引作业的最有效格式,但我已经在其他帖子中进行了探讨。如果我没记错的话,直接分配到data的{​​{1}}和rows属性的速度会更快,但在一次填充整行时这些属性主要是有价值的。

lil也相对较快,但我发现分配到常规字典,然后更新dok的速度更快。 (A dok是一个字典子类。)

但如果您转到dok路线 - 构建coodatarows值列表,则同时创建colsi,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。