Подход № 1
Используйте np.einsum
для расчета расстояния. Чтобы решить наш случай здесь, мы могли бы сделать -
def dist_matrix_vec(matrix, vec):
d = np.subtract(matrix,vec)
return np.sqrt(np.einsum('ij,ij->i',d,d))
Пробный прогон -
In [251]: A = [[1,2,3],[2,3,4],[8,9,10]]
In [252]: B = np.array([1,1,1])
In [253]: dist_matrix_vec(A,B)
Out[253]: array([ 2.23606798, 3.74165739, 13.92838828])
Подход № 2
При работе с большими данными мы можем использовать numexpr
модуль , который поддерживает многоядерную обработку, если предполагаемые операции могут быть выражены как арифметические. Чтобы решить наш случай, мы можем выразить это так -
import numexpr as ne
def dist_matrix_vec_numexpr(matrix, vec):
matrix = np.asarray(matrix)
vec = np.asarray(vec)
return np.sqrt(ne.evaluate('sum((matrix-vec)**2,1)'))
Синхронизация на больших массивах -
In [295]: np.random.seed(0)
...: A = np.random.randint(0,9,(10000,3))
...: B = np.random.randint(0,9,(3,))
In [296]: %timeit np.linalg.norm(A - B, axis = 1) #@Nathaniel's soln
...: %timeit dist_matrix_vec(A,B)
...: %timeit dist_matrix_vec_numexpr(A,B)
1000 loops, best of 3: 244 µs per loop
10000 loops, best of 3: 131 µs per loop
10000 loops, best of 3: 96.5 µs per loop
In [297]: np.random.seed(0)
...: A = np.random.randint(0,9,(100000,3))
...: B = np.random.randint(0,9,(3,))
In [298]: %timeit np.linalg.norm(A - B, axis = 1) #@Nathaniel's soln
...: %timeit dist_matrix_vec(A,B)
...: %timeit dist_matrix_vec_numexpr(A,B)
100 loops, best of 3: 5.31 ms per loop
1000 loops, best of 3: 1.43 ms per loop
1000 loops, best of 3: 918 µs per loop
Основанный на numexpr
был с 8
потоками. Таким образом, с большим количеством потоков, доступных для вычислений, это должно улучшиться дальше. Related post
о том, как управлять многоядерными функциями.