2017-10-06 54 views
0

我正在使用一個連接矩陣來表示圖形數據結構。 NxM矩陣對應於具有M個頂點的N條邊(它可能具有比頂點更多的邊,這就是爲什麼我使用scipy的csr_matrix)。邊緣的「開始」點由「-1」表示,終點在連通性矩陣中由「1」表示。所有其他值都是0,所以每行只有2個非零值。在scipy中更新稀疏連接矩陣

我需要整合一個「細分」方法,它將有效地更新連接矩陣。目前我正在將連通性矩陣轉換爲稠密矩陣,以便我可以添加新的行/列並更新舊的行。我轉換爲一個密集矩陣,因爲我還沒有找到解決方案來找到更新舊邊連接的列索引(沒有等效的scipy.where),並且csr表示不允許我通過索引來更新值。

from numpy import where, array, zeros, hstack, vstack 
from scipy.sparse import coo_matrix, csr_matrix 

def connectivity_matrix(edges): 
    m = len(edges) 
    data = array([-1] * m + [1] * m) 
    rows = array(list(range(m)) + list(range(m))) 
    cols = array([edge[0] for edge in edges] + [edge[1] for edge in edges]) 
    C = coo_matrix((data, (rows, cols))).asfptype() 
    return C.tocsr() 

def subdivide_edges(C, edge_indices): 
    C = C.todense() 
    num_e = C.shape[0] # number of edges 
    num_v = C.shape[1] # number of vertices 

    for edge in edge_indices: 
     num_e += 1 # increment row (edge count) 
     num_v += 1 # increment column (vertex count) 
     _, start = where(C[edge] == -1.0) 
     _, end = where(C[edge] == 1.0) 
     si = start[0] 
     ei = end[0] 
     # add row 
     r, c = C.shape 
     new_r = zeros((1, c)) 
     C = vstack([C, new_r]) 
     # add column 
     r, c = C.shape 
     new_c = zeros((r, 1)) 
     C = hstack([C, new_c]) 
     # edit edge start/end points 
     C[edge, ei] = 0.0 
     C[edge, num_v - 1] = 1.0 
     # add new edge start/end points 
     C[num_e - 1, ei] = 1.0 
     C[num_e - 1, num_v - 1] = -1.0 

    return csr_matrix(C) 

edges = [(0, 1), (1, 2)] # edge connectivity 
C = connectivity_matrix(edges) 
C = subdivide_edges(C, [0, 1]) 
# new edge connectivity: [(0, 3), (1, 4), (3, 1), (4, 2)] 

回答

0

稀疏矩陣確實有一個nonzero方法(np.where使用np.nonzero)。但看看它的代碼 - 它會返回coo行/列數據。

使用稀疏矩陣從另一個問題遺留下來的:

In [468]: M 
Out[468]: 
<5x5 sparse matrix of type '<class 'numpy.float64'>' 
    with 5 stored elements in COOrdinate format> 
In [469]: Mc = M.tocsr() 
In [470]: Mc.nonzero() 
Out[470]: (array([0, 1, 2, 3, 4], dtype=int32), array([2, 0, 4, 3, 1], dtype=int32)) 
In [471]: Mc[1,:].nonzero() 
Out[471]: (array([0]), array([0])) 
In [472]: Mc[3,:].nonzero() 
Out[472]: (array([0]), array([3])) 

我轉換成csr做行索引。

還有一個稀疏vstack

但與稀疏矩陣相比,稀疏矩陣的迭代工作比較慢。

請注意浮動比較,如C[edge] == -1.0==測試用整數更好地工作。從零到非零

更改值並引發警告,但沒有工作:

In [473]: Mc[1,1] = 23 
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:774: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient. 
    SparseEfficiencyWarning) 
In [474]: (Mc[1,:]==23).nonzero() 
Out[474]: (array([0]), array([1])) 

更改非零爲零不會產生警告,但它也不會改變基本的稀疏(直到矩陣清理)。 lil格式更適合逐元素更改。

In [478]: Ml = M.tolil() 
In [479]: Ml.nonzero() 
Out[479]: (array([0, 1, 2, 3, 4], dtype=int32), array([2, 0, 4, 3, 1], dtype=int32)) 
In [480]: Ml[1,:].nonzero() 
Out[480]: (array([0], dtype=int32), array([0], dtype=int32)) 
In [481]: Ml[1,2]=.5 
In [482]: Ml[1,:].nonzero() 
Out[482]: (array([0, 0], dtype=int32), array([0, 2], dtype=int32)) 
In [483]: (Ml[1,:]==.5).nonzero() 
Out[483]: (array([0], dtype=int32), array([2], dtype=int32)) 

In [486]: sparse.vstack((Ml,Ml),format='lil') 
Out[486]: 
<10x5 sparse matrix of type '<class 'numpy.float64'>' 
    with 12 stored elements in LInked List format> 

sparse.vstack作品通過轉換輸入coo,和連接它們的屬性(行,COLS,數據),以及製備新的矩陣。

我懷疑你的代碼可以與lil矩陣一起工作,沒有太多的改變。但它可能會變慢。當在低密度矩陣上進行矩陣乘法等時,稀疏獲得最佳速度。當密集等價物太大而不適合存儲器時,它也有幫助。但對於迭代工作和不斷增長的矩陣來說,它很慢。