2016-11-06 178 views
1

有沒有一種簡單而有效的方法來使一個稀疏的scipy矩陣(例如lil_matrix或csr_matrix)是對稱的?scipy稀疏矩陣的對稱化

當填充一個大的稀疏共生矩陣時,同時填寫[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的稀疏矩陣。

回答

3

好吧,它增加了賦值語句的數量,但是在大圖中懲罰是多少?

lil是索引賦值最有效的格式,但我在其他文章的替代方案中進行了探索。如果我沒有記錯的話,直接分配到datarows屬性的lil會更快,儘管這在一次填充整行時主要是有價值的。

一個dok也比較快,但我發現,分配到一個普通的字典,然後更新到dok也較快。 (A dok是一個字典子類)。

但是如果你去了coo路線 - 的datarowscols價值的樓宇名單,創造既i,jj,i而言,一旦成本不高。如果你可以一次定義一堆值,那更好,而不是迭代所有的i,j

因此,高效地創建對稱矩陣只是有效矩陣定義問題的一個子集。

我不知道稀疏包中有任何對稱化函數。我不知道任何線性代數函數是否有對稱規定。我懷疑最有效的處理程序只是假設矩陣是上或下三角形,沒有明確的對稱值。

您可能會創建一個上三角矩陣,然後將這些值複製到下方。在密集的情況下,最簡單的方法是對矩陣和它的轉置進行求和(並且可能減去對角線)。但稀疏矩陣求和有點高效,所以可能不是最好的。但我沒有做任何測試。

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

轉置的總和ATLEAST沒有給我任何的警告效率:轉置的

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

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

它可能快一點,使上三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指數求和)來解決。但它提供瞭如何將樣式輸入收集到較大的塊中的想法。