Transmisión avanzada de indexación numpy

Tengo una matriz de valores por ejemplo

x = array([[[-0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487, 0. , 0. , 0. , 0. ], [ 0. , -0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487, 0. , 0. , 0. ], [ 0. , 0. , 0. , -0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487, 0. ], [ 0. , 0. , 0. , 0. , -0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487]], [[-0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487, 0. , 0. , 0. , 0. ], [ 0. , -0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487, 0. , 0. , 0. ], [ 0. , 0. , 0. , -0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487, 0. ], [ 0. , 0. , 0. , 0. , -0.78867513, -0.21132487, 0. , 0.78867513, 0.21132487]]]) 

Quiero usar la indexación avanzada para extraer los valores distintos de cero. Conozco los índices de los valores distintos de cero por lo que

 idx = array([[4, 3, 1, 0], [5, 4, 2, 1], [7, 6, 4, 3], [8, 7, 5, 4]]) 

El resultado deseado sería algo así como

 x[idx] = array([[[-0.78867513, -0.21132487, 0.78867513, 0.21132487], [-0.78867513, -0.21132487, 0.78867513, 0.21132487], [-0.78867513, -0.21132487, 0.78867513, 0.21132487], [-0.78867513, -0.21132487, 0.78867513, 0.21132487]], [[-0.78867513, -0.21132487, 0.78867513, 0.21132487], [-0.78867513, -0.21132487, 0.78867513, 0.21132487], [-0.78867513, -0.21132487, 0.78867513, 0.21132487], [-0.78867513, -0.21132487, 0.78867513, 0.21132487]]]) 

La matriz x real es mucho más grande en la primera dimensión, pero la estructura distinta de cero siempre está indicada por idx así que la necesito para transmitir a lo largo de la primera dimensión. es posible?

EDITAR: Para que quede claro x largo de la primera dimensión contiene una lista anidada de 4 x 9 array. idx luego tiene las entradas que no son cero fila por fila. Observe en la primera fila de ambas matrices anidadas 4 x 9 en x que las entradas 4 3 1 0 son distintas de cero.

Prueba este:

 x[:,np.arange(idx.shape[0])[:,None],idx] 

Usando esta técnica, cada elemento en np.arange(idx.shape[0])[:,None] (que tiene forma (idx.shape [0], 1) y por lo tanto es un vector de columna) se transmitirá con cada fila en idx Esto se utilizará para todas las entradas a lo largo del primer eje de x.

Intenté este forro para su problema y parece que hace el trabajo sin necesidad de idx . Es posible que deba cambiar el parámetro en .reshape() acuerdo con el tamaño de su problema.

 np.array(filter(lambda x: x!=0, x.ravel())).reshape(-1, 4, 4) 

Aplana la matriz, elimina los ceros y luego los vuelve a cambiar a la forma requerida.

Aquí hay otra versión que probablemente sea más eficiente, ya que no usa la función de filter y en su lugar usa la indexación booleana para matrices numpy

 y = x.ravel() z = y[y!=0].reshape(-1, 4, 4) 

EDITAR:

Mientras jugaba con Numpy, descubrí otra forma de hacerlo.

 x[x!=0].reshape(-1, 4, 4) 

Y aquí está el rendimiento de los tres métodos:

  • Método 1: 10000 loops, best of 3: 21.2 µs per loop
  • Método 2: 100000 loops, best of 3: 2.42 µs per loop
  • Método 3: 100000 loops, best of 3: 1.97 µs per loop

OK, esto es un poco extraño, pero aquí va …

 idxes = np.ones((x.shape[0], x.shape[1], 1), dtype=bool) * idx print x[np.array(x, dtype=bool)].reshape(idxes.shape) 

Y, por supuesto, debes recordar escribir np.array lugar de un array .

¡Aclamaciones!

Y puede descargarse de la computación idx con lo siguiente:

 y = x[np.array(x, dtype=bool)] print y.reshape(x.shape[0], x.shape[1], y.size/x.shape[0]/x.shape[1]) 

Con esto o las líneas de arriba, es el lanzamiento de los flotadores como bolas que proporciona una máscara que elimina los ceros.