web-dev-qa-db-ja.com

Scipy sparse ... array?

だから、私はかなりまばらなnumpy配列を使用していくつかのKmeans分類を行っています-たくさんのゼロ。ストレージのオーバーヘッドを削減するためにscipyの「スパース」パッケージを使用すると思いましたが、マトリックスではなく配列の作成方法について少し混乱しています。

スパース行列の作成方法に関するこのチュートリアルを完了しました: http://www.scipy.org/SciPy_Tutorial#head-c60163f2fd2bab79edd94be43682414f18b90df7

配列を模倣するために、1xN行列を作成しますが、ご想像のとおり、Asp.dot(Bsp)は2つの1xN行列を乗算できないためうまく機能しません。各配列をNx1に転置する必要があります。これは、すべての内積計算で実行するため、非常に不十分です。

次に、列1 ==行1のNxNマトリックスを作成しようとしました(2つのマトリックスを乗算して、左上隅をドット積として取得できるようにします)が、それは非常に非効率的であることが判明しました。

Numpyのarray()の魔法の代替としてscipyのスパースパッケージを使用したいのですが、まだ、何をすべきか本当にわかりません。

何かアドバイス?

48
spitzanator

行または列ベースの_scipy.sparse_形式を使用します:_csc_matrix_および_csr_matrix_。

これらは内部で効率的なC実装(乗算を含む)を使用し、転置は何も行いません(特にtranspose(copy=False)を呼び出す場合)、numpy配列の場合と同様です。

編集: ipython によるいくつかのタイミング:

_import numpy, scipy.sparse
n = 100000
x = (numpy.random.Rand(n) * 2).astype(int).astype(float) # 50% sparse vector
x_csr = scipy.sparse.csr_matrix(x)
x_dok = scipy.sparse.dok_matrix(x.reshape(x_csr.shape))
_

これで_x_csr_と_x_dok_は50%スパースになります:

_print repr(x_csr)
<1x100000 sparse matrix of type '<type 'numpy.float64'>'
        with 49757 stored elements in Compressed Sparse Row format>
_

そしてタイミング:

_timeit numpy.dot(x, x)
10000 loops, best of 3: 123 us per loop

timeit x_dok * x_dok.T
1 loops, best of 3: 1.73 s per loop

timeit x_csr.multiply(x_csr).sum()
1000 loops, best of 3: 1.64 ms per loop

timeit x_csr * x_csr.T
100 loops, best of 3: 3.62 ms per loop
_

だから嘘をついたようです。転置isは非常に安価ですが、csr * cscの効率的なC実装はありません(最新のscipy 0.9.0)。新しいcsrオブジェクトは、各呼び出しで構築されます:-(

ハックとして(最近はscipyは比較的安定しています)、スパースデータに対して直接ドット積を行うことができます。

_timeit numpy.dot(x_csr.data, x_csr.data)
10000 loops, best of 3: 62.9 us per loop
_

この最後のアプローチは、numpyの密乗算を再び行うことに注意してください。スパース性は50%なので、実際にはdot(x, x)より2倍速くなります。

34
Radim

既存の2Dスパース配列のいずれかのサブクラスを作成できます

from scipy.sparse import dok_matrix

class sparse1d(dok_matrix):
    def __init__(self, v):
        dok_matrix.__init__(self, (v,))
    def dot(self, other):
        return dok_matrix.dot(self, other.transpose())[0,0]

a=sparse1d((1,2,3))
b=sparse1d((4,5,6))
print a.dot(b)
1
John La Rooy

私はそれが本当にはるかに優れているか高速かはわかりませんが、これを行うことで転置の使用を避けることができます:

Asp.multiply(Bsp).sum()

これは、2つの行列の要素ごとの積を取得し、その積を合計するだけです。上記のステートメントをドット積として使用しているマトリックス形式のサブクラスを作成できます。

ただし、それらを転記する方がおそらく簡単です:

Asp*Bsp.T

これはそれほど面倒ではないようですが、サブクラスを作成してmul()メソッドを変更することもできます。

1
Justin Peel