【问题标题】:Symmetrization of scipy sparse matricesscipy稀疏矩阵的对称化
【发布时间】:2017-03-20 04:02:57
【问题描述】:

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

【问题讨论】:

    标签: python numpy scipy


    【解决方案1】:

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

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

    这应该适用于除 coo_matrix 之外的所有类型的 scipy 稀疏矩阵。

    编辑:注明 coo_matrix。

    【讨论】:

    • 这不适用于 coo 矩阵。但也适用于其他类型。
    • 得到 ValueError:分配中的形状不匹配。知道为什么吗?
    • @Null_Space 是你的矩阵吗?上面的代码仅适用于具有相同行数和列数的矩阵。例如,如果有 10 行但 >10 列,您可能可以使用 sparse_matrix[cols[:10], rows] = sparse_matrix[rows, cols[:10]] 来对称化非方阵。
    【解决方案2】:

    好的,它使赋值语句的数量翻了一番,但总的来说,这是多少惩罚?

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

    ================

    制作上面的tri coo矩阵可能会快一点,并通过列表(或数组)连接扩展到下面

    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 样式输入收集到更大的块中的想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-09
      • 1970-01-01
      • 1970-01-01
      • 2017-03-26
      • 2017-03-31
      • 2023-04-10
      • 2017-07-21
      • 2011-11-28
      相关资源
      最近更新 更多