2012-08-26 51 views
7

行列をCSR形式にすると、行(または行)をゼロに設定する最も効率的な方法は何ですか?scipy.sparse:ゼロを0に設定

次のコードは、非常にゆっくりと実行されます。

A = A.tolil() 
A[indices, :] = 0 
A = A.tocsr() 

私はCSRフォーマットはスライスに空想のインデックスや設定値のいずれをサポートするように見えるので、scipy.sparse.lil_matrixに変換しなければなりませんでした。私は推測

+0

まあ、私はちょうど '[A .__ SetItem関数__((i、j)が、0)を試してみました(A.シェイプ[1])]と 'SciPy'は、' SparseEfficiencyWarning:csr_matrixのスパース性構造を変更するのは高価です。 lil_matrixはより効率的です。」... –

+0

scipyがそれをサポートしているかどうかは分かりませんが、CSRマトリクスであるため、これは効率的に(少なくとも手作業で)処理できます。 1つの質問は、希薄パターンを変更したいのですか、それらの0は数値的に0にすべきですか? – seberg

+0

スパースパターンが何を意味するのかよく分かりません。私はscipy.sparse.linalg.spsolve関数を使って方程式系を解くことに進みます。私はこれがスパースパターンを変更する必要性を確立しているか、その欠如を望みます。 –

答えて

5

はそれを実装していないscipyのダウンロードが、CSRのフォーマットは非常によくこれを支持するだろう、などが何であるかindptrについて「スパース行列」のWikipediaの記事をご覧ください:もちろん

# A.indptr is an array, one for each row (+1 for the nnz): 

def csr_row_set_nz_to_val(csr, row, value=0): 
    """Set all nonzero elements (elements currently in the sparsity pattern) 
    to the given value. Useful to set to 0 mostly. 
    """ 
    if not isinstance(csr, scipy.sparse.csr_matrix): 
     raise ValueError('Matrix given must be of CSR format.') 
    csr.data[csr.indptr[row]:csr.indptr[row+1]] = value 

# Now you can just do: 
for row in indices: 
    csr_row_set_nz_to_val(A, row, 0) 

# And to remove zeros from the sparsity pattern: 
A.eliminate_zeros() 

スパース性パターンからeliminate_zerosで別の場所から設定された0を削除します。あなたがそれをしたいのであれば(現時点では)、あなたが本当にやっていること、すなわち、それに依存します。新しいゼロを追加する可能性のある他のすべての計算が完了するまで、または後で再び変更したい0の値を持つことがある場合があるため、それらを削除することは非常に悪い場合があります。

もちろん、eliminate_zerospruneを短絡させることはできますが、それは面倒ですばらしく、さらに遅くなる可能性があります(Cでは実行しないため)。 eliminiate_zeros(プルーン)約


詳細

疎行列、一般にゼロ要素を保存し、ちょうどゼロでない要素が(おおよそ様々な方法で)され格納されません。 eliminate_zerosは、希薄パターンからマトリックス内のすべてのゼロを削除します(つまり、の前に、の値が格納されていても、その位置が0であったとき)。後で0を別の値に変更したい場合は削除してください。削除しないと、領域が節約されます。

プルーンは、必要以上に長くなったときに格納されたデータ配列を縮小するだけです。私が最初にA.prune()を持っていた間に、A.eliminiate_zeros()にはすでにプルーンが含まれていることに注意してください。

+0

ありがとう!それはかなり物事を急上昇させた! elimin_zerosとprune文がそこで何をしているのか知りたいのですが? –

+0

文章を追加しました。 'prune()'は不要であり、 'eliminate_zeros'はすでに' prune'を呼び出しています。 – seberg

0

最新のscipyに更新されました。それは空想的な索引付けをサポートします。

0

マトリクスドットプロダクトを使用して、そのゼロ調整を実現できます。使用する行列は非常にまばらです(ゼロにする行/列の対角)ので、乗算は効率的でなければなりません。

次の関数のいずれかが必要になります:

import scipy.sparse 

def zero_rows(M, rows): 
    diag = scipy.sparse.eye(M.shape[0]).tolil() 
    for r in rows: 
     diag[r, r] = 0 
    return diag.dot(M) 

def zero_columns(M, columns): 
    diag = scipy.sparse.eye(M.shape[1]).tolil() 
    for c in columns: 
     diag[c, c] = 0 
    return M.dot(diag) 

使用例:

>>> A = scipy.sparse.csr_matrix([[1,0,3,4], [5,6,0,8], [9,10,11,0]]) 
>>> A 
<3x4 sparse matrix of type '<class 'numpy.int64'>' 
     with 9 stored elements in Compressed Sparse Row format> 
>>> A.toarray() 
array([[ 1, 0, 3, 4], 
     [ 5, 6, 0, 8], 
     [ 9, 10, 11, 0]], dtype=int64) 

>>> B = zero_rows(A, [1]) 
>>> B 
<3x4 sparse matrix of type '<class 'numpy.float64'>' 
     with 6 stored elements in Compressed Sparse Row format> 
>>> B.toarray() 
array([[ 1., 0., 3., 4.], 
     [ 0., 0., 0., 0.], 
     [ 9., 10., 11., 0.]]) 

>>> C = zero_columns(A, [1, 3]) 
>>> C 
<3x4 sparse matrix of type '<class 'numpy.float64'>' 
     with 5 stored elements in Compressed Sparse Row format> 
>>> C.toarray() 
array([[ 1., 0., 3., 0.], 
     [ 5., 0., 0., 0.], 
     [ 9., 0., 11., 0.]]) 
関連する問題