numpy scipy稀疏矩阵的对称化

3pmvbmvn  于 4个月前  发布在  其他
关注(0)|答案(3)|浏览(50)

有没有一种简单有效的方法来使稀疏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稀疏矩阵。

7cwmlq89

7cwmlq891#

好吧,它使赋值语句的数量增加了一倍,但从全局来看,这会带来多大的损失呢?
lil是索引赋值最有效的格式,但我在其他帖子中探索过替代方案。如果我没记错的话,直接赋值给lildatarows属性会更快,尽管这主要是在一次填充整行时有价值。
dok也相对较快,不过我发现先赋值给常规字典,然后更新到dok会更快(dok是字典子类)。
但是如果你走coo路线--构建datarowscols值的列表,一次创建i,jj,i项的成本并不高。如果你可以一次定义一堆值,而不是迭代所有的i,j,那就更好了。
所以有效地创建一个对称矩阵只是有效矩阵定义问题的一个子集。
我不知道sparse包中有任何对称化函数。我想知道是否有任何线性代数函数具有对称规定。我怀疑最有效的处理程序只是假设矩阵是上三角形或下三角形,而没有显式的对称值。
你可以创建一个上三矩阵,然后将值复制到下三矩阵。在密集的情况下,最简单的方法是对矩阵和它的转置求和(可能减去对角线)。但是稀疏矩阵求和有点效率低下,所以这可能不是最好的。但是我没有做任何测试。

转置的和至少不会给我任何给予效率警告:

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]])

它可能有点快,使上层的tricoo矩阵,并扩展到较低的列表(或数组)连接

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


这重复了对角线,我需要以某种方式解决这个问题(重复的coo索引被求和),但它给出了如何将coo风格的输入收集到更大的块中的想法。

k4ymrczo

k4ymrczo2#

是的,肯定有一个更有效和简单的方法。如果你正在创建一个矩阵,hpaulj的答案应该有效,但如果你已经有一个,你可以这样做:

rows, cols = sparse_matrix.nonzero()
sparse_matrix[cols, rows] = sparse_matrix[rows, cols]

字符串
这应该适用于scipy的所有类型的稀疏矩阵,除了coo_matrix。
编辑:注意到coo_matrix。

sqyvllje

sqyvllje3#

可以使用mmwrite函数,它可以将矩阵转换为对称矩阵。它也适用于coo_matrix,而不仅仅适用于csr:

from scipy.io import mmwrite, mmread
import gzip

with gzip.open("mat.gz", "wb") as f_out:
    mmwrite(f_out, mat, symmetry="symmetric")

sym_mat = mmread("mat.gz)

字符串

相关问题