2017-10-06 14 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.wherenp.nonzeroを使用する)を持っています。しかし、そのコードを見てください - coo行/ colsデータを返します。

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形式は要素ごとに変更する方が適しています。 cooへの入力を変換し、それらの属性(行、COLS、データ)を接合し、新しい行列を作ることにより

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作品。

あなたのコードはあまりにも多くの変更を加えることなくlilマトリックスで動作すると思われます。しかし、それはおそらく遅くなります。低密度マトリックス上の行列乗算のような処理を行う場合、Sparseは最高の速度を得ます。密な等価物が大きすぎてメモリに収まらない場合にも役立ちます。しかし、反復作業と行列の成長は遅いです。

関連する問題