A_{ij}
特定の vectorb_i
と別のmatrix から新しい matrix を作成する高速な方法を探していC_{ij}
ます。新しいマトリックスのコンポーネントは、次の形式にする必要があります。
A_{ij} = b_i * C_{ij}.
ここまでは を使ってdot(diag(b), C)
いますが、内積は当然ゼロとの掛け算が多く、かなり非効率です。より良い方法はありますか?
*
適切なブロードキャストで要素ごとの積である を使用します。
>>> b = array([1,2,3])
>>> C = arange(9).reshape(3,3)
>>> dot(diag(b), C)
array([[ 0, 1, 2],
[ 6, 8, 10],
[18, 21, 24]])
>>> atleast_2d(b).T * C
array([[ 0, 1, 2],
[ 6, 8, 10],
[18, 21, 24]])
atleast_2d(b).T
(またはb.reshape(-1,1)
) ベクトルb
を列ベクトルに再形成します。
einsumも使用できます。
>>> b = np.array([1,2,3])
>>> C = np.arange(9).reshape(3,3)
>>> np.einsum('i,ij->ij', b, C)
array([[ 0, 1, 2],
[ 6, 8, 10],
[18, 21, 24]])
私のマシンでは、この方法は両方よりも高速です
np.dot(np.diag(b), C)
と
np.atleast_2d(b).T * C
100,000 ループの場合、einsum は 1.16 秒、dot は 1.61 秒、atleast_2d は 2.03 秒かかります。
Einstein summation notationに精通している場合、einsum は非常に便利な関数です。インデックス表記を使用すると、多くの単純な線形代数演算を定式化する方が簡単であり、追加された実行速度はケーキのアイシングです。
行列を配列に変換し、(ブロードキャスト)配列乗算を実行して、元に戻します。
np.matrix(b * np.asarray(C))
行う
b[:,np.newaxis] * C
また
b[:,None] * C
すでに与えられた答えを組み合わせて、新しい(しかし非効率的な方法)を試してみると、次のタイミングになります。
einsum とブロードキャストをそれぞれ 10 回繰り返すと (より正確なタイミング)、次のことがわかります。
そのためのテストコードは次のとおりです。
import timeit
from scipy.sparse.dia import dia_matrix
import numpy as np
def get_bc():
N = 10000
M = 10000
b = np.random.random(size=N)
c = np.random.random(size=[N, M])
return b, c
def multiply_dot_diag():
global b, c
return np.dot(np.diag(b), c)
def multiply_broadcast():
global b, c
return np.atleast_2d(b).T * c
def mulitply_sparse():
global b, c
N = b.size
return dia_matrix((b, 0), shape=[N, N]).todense().dot(c)
def multiply_einsum():
global b, c
return np.einsum('i,ij->ij', b, c)
if __name__ == '__main__':
global b, c
b, c = get_bc()
print (b, c)
print (timeit.timeit(multiply_einsum, number=1))
print (timeit.timeit(multiply_broadcast, number=1))
print (timeit.timeit(multiply_dot_diag, number=1))
print (timeit.timeit(mulitply_sparse, number=1))
np.testing.assert_array_equal(multiply_dot_diag(), multiply_broadcast())
np.testing.assert_array_equal(multiply_dot_diag(), mulitply_sparse())
np.testing.assert_array_equal(multiply_dot_diag(), multiply_einsum())