Manera vectorizada de calcular el producto de punto fila-dos matrices con Scipy

Quiero calcular el producto de puntos fila de dos matrices de la misma dimensión lo más rápido posible. Esta es la forma en que lo estoy haciendo:

import numpy as np a = np.array([[1,2,3], [3,4,5]]) b = np.array([[1,2,3], [1,2,3]]) result = np.array([]) for row1, row2 in a, b: result = np.append(result, np.dot(row1, row2)) print result 

y por supuesto la salida es:

 [ 26. 14.] 

Mira numpy.einsum para otro método:

 In [52]: a Out[52]: array([[1, 2, 3], [3, 4, 5]]) In [53]: b Out[53]: array([[1, 2, 3], [1, 2, 3]]) In [54]: einsum('ij,ij->i', a, b) Out[54]: array([14, 26]) 

Parece que einsum es un poco más rápido que inner1d :

 In [94]: %timeit inner1d(a,b) 1000000 loops, best of 3: 1.8 us per loop In [95]: %timeit einsum('ij,ij->i', a, b) 1000000 loops, best of 3: 1.6 us per loop In [96]: a = random.randn(10, 100) In [97]: b = random.randn(10, 100) In [98]: %timeit inner1d(a,b) 100000 loops, best of 3: 2.89 us per loop In [99]: %timeit einsum('ij,ij->i', a, b) 100000 loops, best of 3: 2.03 us per loop 

La forma directa de hacerlo es:

 import numpy as np a=np.array([[1,2,3],[3,4,5]]) b=np.array([[1,2,3],[1,2,3]]) np.sum(a*b, axis=1) 

que evita el bucle python y es más rápido en casos como:

 def npsumdot(x, y): return np.sum(x*y, axis=1) def loopdot(x, y): result = np.empty((x.shape[0])) for i in range(x.shape[0]): result[i] = np.dot(x[i], y[i]) return result timeit npsumdot(np.random.rand(500000,50),np.random.rand(500000,50)) # 1 loops, best of 3: 861 ms per loop timeit loopdot(np.random.rand(500000,50),np.random.rand(500000,50)) # 1 loops, best of 3: 1.58 s per loop 

inner1d con esto y encontramos inner1d el más rápido:

enter image description here

La ttwig fue creada con perfplot (un pequeño proyecto mío)

 import numpy from numpy.core.umath_tests import inner1d import perfplot perfplot.show( setup=lambda n: (numpy.random.rand(n, 3), numpy.random.rand(n, 3)), n_range=[2**k for k in range(1, 18)], kernels=[ lambda data: numpy.sum(data[0] * data[1], axis=1), lambda data: numpy.einsum('ij, ij->i', data[0], data[1]), lambda data: inner1d(data[0], data[1]) ], labels=['np.sum(a*b, axis=1)', 'einsum', 'inner1d'], logx=True, logy=True, xlabel='len(a), len(b)' ) 

Lo mejor será evitar el append , pero no puedo pensar en una forma de evitar el ciclo de Python. ¿Un Ufunc personalizado tal vez? No creo que numpy.vectorize te ayude aquí.

 import numpy as np a=np.array([[1,2,3],[3,4,5]]) b=np.array([[1,2,3],[1,2,3]]) result=np.empty((2,)) for i in range(2): result[i] = np.dot(a[i],b[i])) print result 

EDITAR

Según esta respuesta , parece que inner1d podría funcionar si los vectores en su problema del mundo real son 1D.

 from numpy.core.umath_tests import inner1d inner1d(a,b) # array([14, 26]) 
Intereting Posts