2012-05-20 18 views
9

Decir que tengo dos matrices a y b,elementwise multiplicación de matrices de diferentes formas en pitón

a.shape = (5,2,3) 
    b.shape = (2,3) 

continuación c = a * b me dará una matriz de forma c(5,2,3) con c[i,j,k] = a[i,j,k]*b[j,k].

Ahora la situación es,

a.shape = (5,2,3) 
    b.shape = (2,3,8) 

y quiero c para tener una forma (5,2,3,8) con c[i,j,k,l] = a[i,j,k]*b[j,k,l].

¿Cómo hacer esto de manera eficiente? Mi a y b son en realidad bastante grandes.

Respuesta

13

Esto debería funcionar:

a[..., numpy.newaxis] * b[numpy.newaxis, ...] 

Uso:

In : a = numpy.random.randn(5,2,3) 

In : b = numpy.random.randn(2,3,8) 

In : c = a[..., numpy.newaxis]*b[numpy.newaxis, ...] 

In : c.shape 
Out: (5, 2, 3, 8) 

Ref: Array Broadcasting in numpy

Edición: URL actualizada de referencia

+0

Me parece que 'None' también funciona, además de' numpy.newaxis'; y de hecho, ese 'numpy.newaxis es None' es cierto para mí. ¿Hay alguna razón para no usar 'None' aquí? – senderle

+1

@senderle. Aparentemente, son intercambiables: [numpy.newaxis] (http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#numpy.newaxis). Pero, en el futuro, podría cambiar. Supongo que es por eso que pusieron 'newaxis' allí como sinónimo de' None'. – Avaris

+0

'np.newaxis is None' devuelve' True'.Tiendo a usar 'newaxis' solo para hacer cosas explícitas en mi código. También vea http://stackoverflow.com/questions/944863/numpy-should-i-use-newaxis-or-none – JoshAdel

7

Creo que el siguiente debería funcionar:

import numpy as np 
a = np.random.normal(size=(5,2,3)) 
b = np.random.normal(size=(2,3,8)) 
c = np.einsum('ijk,jkl->ijkl',a,b) 

y:

In [5]: c.shape 
Out[5]: (5, 2, 3, 8) 

In [6]: a[0,0,1]*b[0,1,2] 
Out[6]: -0.041308376453821738 

In [7]: c[0,0,1,2] 
Out[7]: -0.041308376453821738 

np.einsum puede ser un poco difícil de usar, pero es bastante potente para este tipo de problemas de indexación:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum.html

También tenga en cuenta que t su requiere numpy> = v1.6.0

No estoy seguro acerca de la eficiencia para su problema en particular, pero si no funciona tan bien como se necesita, definitivamente analice el uso de Cython con bucles explicitos, y posiblemente paralelizarlo utilizando prange

ACTUALIZACIÓN

In [18]: %timeit np.einsum('ijk,jkl->ijkl',a,b) 
100000 loops, best of 3: 4.78 us per loop 

In [19]: %timeit a[..., np.newaxis]*b[np.newaxis, ...] 
100000 loops, best of 3: 12.2 us per loop 


In [20]: a = np.random.normal(size=(50,20,30)) 
In [21]: b = np.random.normal(size=(20,30,80)) 

In [22]: %timeit np.einsum('ijk,jkl->ijkl',a,b) 
100 loops, best of 3: 16.6 ms per loop 

In [23]: %timeit a[..., np.newaxis]*b[np.newaxis, ...] 
100 loops, best of 3: 16.6 ms per loop 

In [2]: a = np.random.normal(size=(500,20,30)) 
In [3]: b = np.random.normal(size=(20,30,800)) 

In [4]: %timeit np.einsum('ijk,jkl->ijkl',a,b) 
1 loops, best of 3: 3.31 s per loop 

In [5]: %timeit a[..., np.newaxis]*b[np.newaxis, ...] 
1 loops, best of 3: 2.6 s per loop 
+0

Umm, bueno ... Para más grandes arrays 'numpy.einsum' parece ser un poco más lento. – Avaris

+0

@Avaris En general, estoy de acuerdo con su evaluación de los tiempos, aunque en una amplia gama de tamaños de matriz, 'np.einsum' es tan rápido o más rápido que la solución de transmisión. De alguna manera, prefiero la solución de einsum para la legibilidad y hacer las cosas explícitas, aunque otros pueden estar en desacuerdo. Pero sin duda, si para el caso de uso, la transmisión es más rápida, úselo. – JoshAdel

+0

No sabía sobre 'np.einsum' ... muy bien. – mgilson

Cuestiones relacionadas