SciPy sparse matrix を取得しました。たとえば、CSR 形式で、一致する長さA
のベクトルがあります。v
を使用して行をスケーリングA
するv
、つまり実行
する最良の方法は何diag(v) * A
ですか?
SciPy sparse matrix を取得しました。たとえば、CSR 形式で、一致する長さA
のベクトルがあります。v
を使用して行をスケーリングA
するv
、つまり実行
する最良の方法は何diag(v) * A
ですか?
簡単な方法は、scipy に面倒な詳細を処理させ、次のようにすることです。
scipy.sparse.spdiags(v, 0, len(v), len(v)) * A
編集マトリックスがCSC形式で保存されている場合(およびその場合のみ)、次のように操作を行うことができます:
A_csc.data = A_csc.data * v[A_csc.indices]
マトリックスのスパース性とそのサイズに大きく依存するため、いくつかのタイミングを実行しました。次のコードで自由に遊んでください。
from __future__ import division
import numpy as np
import scipy.sparse as sps
import timeit
A_csr = None
A_csc = None
v = None
def time_row_scaling(n, dens) :
global A_csr, A_csc, v
v = np.random.rand(n)
A_csr = sps.rand(n, n, density=dens, format='csr')
A_csc = A_csr.tocsc()
def row_scale(A_csc, v) :
A_csc.data = A_csc.data * v[A_csc.indices]
row_scaled_1 = sps.spdiags(v, 0, n , n) * A_csr
row_scaled_2 = sps.spdiags(v, 0, n , n) * A_csc
row_scale(A_csc, v)
if n < 1000 :
np.testing.assert_almost_equal(row_scaled_1.toarray(),
row_scaled_2.toarray())
np.testing.assert_almost_equal(row_scaled_1.toarray(),
A_csc.toarray())
A_csc = A_csr.tocsc()
t1 = timeit.timeit('sps.spdiags(v, 0, len(v) , len(v)) * A_csr',
'from __main__ import sps, v, A_csr',
number=1)
t2 = timeit.timeit('sps.spdiags(v, 0, len(v), len(v)) * A_csc',
'from __main__ import sps, v, A_csc',
number=1)
t3 = timeit.timeit('A_csc.data = A_csc.data * v[A_csc.indices]',
'from __main__ import A_csc, v',
number=1)
print t1, t2, t3
>>> time_row_scaling(1000, 0.01)
0.00100659830939 0.00102425072673 0.000231944553347
>>> time_row_scaling(1000, 0.1)
0.0017328105481 0.00311339379218 0.00239826562947
>>> time_row_scaling(10000, 0.01)
0.0162369397769 0.0359325217874 0.0216837368279
>>> time_row_scaling(10000, 0.1)
0.167978350747 0.492032396702 0.209231639536
要約すると、それがCSRの場合、または本当に大きい場合は、単純な最初の方法を使用してください。それが小さく、非常にまばらな行列である場合、すべての時間は小さくなりますが、その場での方法の方が高速です。
sklearn は でこれを行うためのユーティリティを提供しますsklearn.utils.sparsefuncs.inplace_csr_row_scale
。私の実験では、これはJaimeが提案した方法とその方法よりもわずかに優れていましたcsr_matrix.multiply
. 私の実験では、10^7 x 10^4 程度の非常に大きな行列が使用されていることに注意してください。このサイズの行列の場合、sklearn は約 2 秒かかります。他の方法の範囲は 2.5 ~ 5 秒です。
しかし、これを達成する最も効率的な方法は、提供されているmkl_?csrmultcsrメソッドと対角行列を使用して MKL にフックすることです。
私のラッパーはまだバグが多すぎるため、そのためのコードを提供していませんが、これは上記で使用したのと同じサイズの行列に対して約 0.3 秒で再スケーリングを実行します。
おそらくいつか numpy/scipy は密な数学の場合と同じように、疎な数学のために MKL にフックするでしょう...