Мы можем использовать комбинацию np.einsum
и np.tensordot
-
a = np.einsum('ijk,ijk,ijk->k',values1,values2,weight)
out = np.tensordot(a,is_relevant,axes=(0,2))
В качестве альтернативы, с одним einsum
вызовом -
np.einsum('ijk,ijk,ijk,lmk->lm',values1,values2,weight,is_relevant)
А с np.dot
и einsum
-
is_relevant.dot(np.einsum('ijk,ijk,ijk->k',values1,values2,weight))
Кроме того, поэкспериментируйте с флагом optimize
в np.einsum
, установив его как True
для использования BLAS.
Сроки -
In [146]: %%timeit
...: a = np.einsum('ijk,ijk,ijk->k',values1,values2,weight)
...: out = np.tensordot(a,is_relevant,axes=(0,2))
10000 loops, best of 3: 121 µs per loop
In [147]: %timeit np.einsum('ijk,ijk,ijk,lmk->lm',values1,values2,weight,is_relevant)
1000 loops, best of 3: 851 µs per loop
In [148]: %timeit np.einsum('ijk,ijk,ijk,lmk->lm',values1,values2,weight,is_relevant,optimize=True)
1000 loops, best of 3: 347 µs per loop
In [156]: %timeit is_relevant.dot(np.einsum('ijk,ijk,ijk->k',values1,values2,weight))
10000 loops, best of 3: 58.6 µs per loop
Очень большие массивы
Для очень больших массивов мы можем использовать numexpr
, чтобы использовать multi-cores
-
import numexpr as ne
a = np.einsum('ijk,ijk,ijk->k',values1,values2,weight)
out = np.empty((N, M))
for i in range(N):
for j in range(M):
out[i,j] = ne.evaluate('sum(is_relevant_ij*a)',{'is_relevant_ij':is_relevant[i,j], 'a':a})