2013-01-24 22 views
8

私は論理演算(主に要素ごとのOR)を実行するために必要なブール値でいっぱいのスパース行列のセットを持っています。 numpyののようにscipy.sparse行列のブール演算

、DTYPE =「ブール」で行列を合計すると、要素単位のORを与える、しかし厄介な副作用があります:

>>> from scipy import sparse 
>>> [a,b] = [sparse.rand(5,5,density=0.1,format='lil').astype('bool') 
... for x in range(2)] 
>>> b 
<5x5 sparse matrix of type '<class 'numpy.bool_'>' 
    with 2 stored elements in LInked List format> 
>>> a+b 
<5x5 sparse matrix of type '<class 'numpy.int8'>' 
    with 4 stored elements in Compressed Sparse Row format> 

データ型が原因となる、「INT8」に変更されます将来の操作の問題。

(a+b).astype('bool') 

しかし、私はこのタイプの変更によってパフォーマンスが低下するという印象を受けます。

結果のdtypeがオペランドと異なるのはなぜですか?
そして、Pythonで疎行列の論理演算を行うより良い方法はありますか?

答えて

5

論理演算はスパース行列ではサポートされていませんが、 'bool'に変換することはそれほど高価ではありません。実際に、LIL形式の行列を使用している場合、変換が原因のパフォーマンスの変動に負の時間がかかるように見えることがあります。

a = scipy.sparse.rand(10000, 10000, density=0.001, format='lil').astype('bool') 
b = scipy.sparse.rand(10000, 10000, density=0.001, format='lil').astype('bool') 

In [2]: %timeit a+b 
10 loops, best of 3: 61.2 ms per loop 

In [3]: %timeit (a+b).astype('bool') 
10 loops, best of 3: 60.4 ms per loop 

あなたのLIL行列はそれらを一緒に追加する前に、CSRのフォーマットに変換されたことに気づいたかもしれません、リターンを見てフォーマット。すでにそもそもCSRのフォーマットを使用していた場合は、変換のオーバーヘッドがより顕著になる:

In [14]: %timeit a+b 
100 loops, best of 3: 2.28 ms per loop 

In [15]: %timeit (a+b).astype(bool) 
100 loops, best of 3: 2.96 ms per loop 

CSR(およびCSC)行列は、実際の非ゼロのエントリを保持している1次元配列であるdata属性を持っていますスパース行列の再計算のコストは、行列のサイズではなく、行列の非ゼロエントリの数に依存します。

a = scipy.sparse.rand(10000, 10000, density=0.0005, format='csr').astype('int8') 
b = scipy.sparse.rand(1000, 1000, density=0.5, format='csr').astype('int8') 

In [4]: %timeit a.astype('bool') # a is 10,000x10,000 with 50,000 non-zero entries 
10000 loops, best of 3: 93.3 us per loop 

In [5]: %timeit b.astype('bool') # b is 1,000x1,000 with 500,000 non-zero entries 
1000 loops, best of 3: 1.7 ms per loop