Expresión elegante para el producto de puntos por filas de dos matrices.

Tengo dos matrices numpy 2-d con las mismas dimensiones, A y B, y estoy tratando de calcular el producto puntual de las filas. Yo podría hacer:

np.sum(A * B, axis=1) 

¿Hay otra manera de hacer esto para que numpy esté haciendo el producto de puntos por filas en un paso en lugar de dos? Tal vez con tensordot ?

Esta es una buena aplicación para numpy.einsum .

 a = np.random.randint(0, 5, size=(6, 4)) b = np.random.randint(0, 5, size=(6, 4)) res1 = np.einsum('ij, ij->i', a, b) res2 = np.sum(a*b, axis=1) print(res1) # [18 6 20 9 16 24] print(np.allclose(res1, res2)) # True 

einsum también tiende a ser un poco más rápido.

 a = np.random.normal(size=(5000, 1000)) b = np.random.normal(size=(5000, 1000)) %timeit np.einsum('ij, ij->i', a, b) # 100 loops, best of 3: 8.4 ms per loop %timeit np.sum(a*b, axis=1) # 10 loops, best of 3: 28.4 ms per loop 

Aún más rápido es inner1d de numpy.core.umath_tests :

introduzca la descripción de la imagen aquí


Código para reproducir la ttwig:

 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)), kernels=[ lambda a: numpy.sum(a[0]*a[1], axis=1), lambda a: numpy.einsum('ij, ij->i', a[0], a[1]), lambda a: inner1d(a[0], a[1]) ], labels=['sum', 'einsum', 'inner1d'], n_range=[2**k for k in range(20)], xlabel='len(a), len(b)', logx=True, logy=True ) 

Aunque es significativamente más lento incluso para tamaños de datos moderados, usaría

 np.diag(A.dot(BT)) 

mientras desarrolla la biblioteca y se preocupa por optimizarla más adelante, cuando se ejecute en una configuración de producción o después de que se escriban las pruebas de unidad.

Para la mayoría de las personas que se encuentran con su código, esto será más comprensible que einsum , y tampoco requiere que rompa algunas de las mejores prácticas incorporando su cálculo dentro de una cadena mini DSL para que sirva de argumento a alguna llamada de función.

Estoy de acuerdo en que vale la pena evitar el cálculo de los elementos fuera de la diagonal para casos grandes. Tendría que ser realmente muy grande para que me preocupara por eso, y la compensación por pagar el horrible precio de express el cálculo en una cadena incrustada en einsum es bastante grave.