2017-10-17 6 views
-2

こんにちは、Aが疎行列であり、ptotalが数値の配列である以下の方程式を解こうとしています。行のすべてのエントリを対角線上の位置に集計する必要があります。行列の対角位置にある行列をPythonで高速に加算する方法

A[ptotal, ptotal] = -sum(A[ptotal, :]) 

コードは、正しい答えを与えているようだが、私のPTOTAL配列が長く、ほぼ(100000個のエントリ)であるから、それは計算上効率的ではありません。この問題を解決する方法はありますか?

+0

'C++'タグは何ですか? 'sparse' - たくさんの0や' scipy.sparse'マトリックスを持つ配列がありますか? 'ptotal'は一意の値ですか、重複していますか?小さなテストケースが役に立ちます。 – hpaulj

+0

その 'scipy.sparse'マトリックスです。 'ptotal'は0から100000までの値の配列です。すべての値は重複していません。 @hpaulj – ZAK

答えて

0

まず稠密アレイバージョン:我々は、これらの値を用いてアレイを作ることができる

In [89]: sum(A[ptotal,:]) 
Out[89]: array([ 90, 96, 102, 108, 114, 120]) 
In [90]: A.sum(axis=0) 
Out[90]: array([ 90, 96, 102, 108, 114, 120]) 

In [87]: A = np.arange(36).reshape(6,6) 
In [88]: ptotal = np.arange(6) 

ptotalと仮定すると、それは、sumメソッド呼び出しに置き換えることができ、全ての行インデックスであります対角線上:

In [92]: np.diagflat(A.sum(axis=0)) 
Out[92]: 
array([[ 90, 0, 0, 0, 0, 0], 
     [ 0, 96, 0, 0, 0, 0], 
     [ 0, 0, 102, 0, 0, 0], 
     [ 0, 0, 0, 108, 0, 0], 
     [ 0, 0, 0, 0, 114, 0], 
     [ 0, 0, 0, 0, 0, 120]]) 

元の配列に追加 - その結果は「ゼロサム」配列である:

In [93]: A -= np.diagflat(A.sum(axis=0)) 
In [94]: A 
Out[94]: 
array([[-90, 1, 2, 3, 4, 5], 
     [ 6, -89, 8, 9, 10, 11], 
     [ 12, 13, -88, 15, 16, 17], 
     [ 18, 19, 20, -87, 22, 23], 
     [ 24, 25, 26, 27, -86, 29], 
     [ 30, 31, 32, 33, 34, -85]]) 
In [95]: A.sum(axis=0) 
Out[95]: array([0, 0, 0, 0, 0, 0]) 

私たちは、スパース

In [99]: M = sparse.csr_matrix(np.arange(36).reshape(6,6)) 
In [100]: M 
Out[100]: 
<6x6 sparse matrix of type '<class 'numpy.int32'>' 
    with 35 stored elements in Compressed Sparse Row format> 
In [101]: M.sum(axis=0) 
Out[101]: matrix([[ 90, 96, 102, 108, 114, 120]], dtype=int32) 

とスパース対角行列同じことを行うことができます:取得、違いを取る

In [104]: sparse.dia_matrix((M.sum(axis=0),0),M.shape) 
Out[104]: 
<6x6 sparse matrix of type '<class 'numpy.int32'>' 
    with 6 stored elements (1 diagonals) in DIAgonal format> 
In [105]: _.A 
Out[105]: 
array([[ 90, 0, 0, 0, 0, 0], 
     [ 0, 96, 0, 0, 0, 0], 
     [ 0, 0, 102, 0, 0, 0], 
     [ 0, 0, 0, 108, 0, 0], 
     [ 0, 0, 0, 0, 114, 0], 
     [ 0, 0, 0, 0, 0, 120]], dtype=int32) 

を新しい行列:

In [106]: M-sparse.dia_matrix((M.sum(axis=0),0),M.shape) 
Out[106]: 
<6x6 sparse matrix of type '<class 'numpy.int32'>' 
    with 36 stored elements in Compressed Sparse Row format> 
In [107]: _.A 
Out[107]: 
array([[-90, 1, 2, 3, 4, 5], 
     [ 6, -89, 8, 9, 10, 11], 
     [ 12, 13, -88, 15, 16, 17], 
     [ 18, 19, 20, -87, 22, 23], 
     [ 24, 25, 26, 27, -86, 29], 
     [ 30, 31, 32, 33, 34, -85]], dtype=int32) 

In [117]: M.setdiag(-M.sum(axis=0).A1) 
/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 [118]: M.A 
Out[118]: 
array([[ -90, 1, 2, 3, 4, 5], 
     [ 6, -96, 8, 9, 10, 11], 
     [ 12, 13, -102, 15, 16, 17], 
     [ 18, 19, 20, -108, 22, 23], 
     [ 24, 25, 26, 27, -114, 29], 
     [ 30, 31, 32, 33, 34, -120]], dtype=int32) 
Out[101]

が2D行列でsetdiag方法もあります。 .A1は、setdiagが使用できる1d配列に変換します。

スパース効率警告は、このような1回限りのアプリケーションよりも繰り返し使用を目指しています。それでも、setdiagのコードを見ると、私は最初のアプローチがより速いと思っています。しかし、実際には時間のテストが必要です。

+0

len(ptotal)= 27000の場合、M-sparse.dia_matrix((M.sum(軸= 0)、0)、Mshape)アプローチは38秒から1.2秒に短縮しました。したがって、時間の大幅な改善があります。ありがとう@hpaulj。 – ZAK