2011-10-19 13 views

Respuesta

19

de page on indexing La documentación de referencia Numpy contiene las respuestas, pero requiere un poco de lectura cuidadosa

La respuesta aquí es que la indexación con booleanos es equivalente a la indexación con matrices de enteros obtenidas al transformar primero las matrices booleanas con np.nonzero. Por lo tanto, con matrices booleanas m1, m2

a[m1, m2] == a[m1.nonzero(), m2.nonzero()] 

cuales (cuando tiene éxito, es decir, m1.nonzero().shape == m2.nonzero().shape) es equivalente a:

[a[i, i] for i in range(a.shape[0]) if m1[i] and m2[i]] 

No estoy seguro de por qué se ha diseñado para funcionar como esto - - por lo general, esto es no lo que desea.

para obtener el resultado más intuitivo, en su lugar puede hacer

a[np.ix_(m1, m2)] 

que produce un resultado equivalente a

[[a[i,j] for j in range(a.shape[1]) if m2[j]] for i in range(a.shape[0]) if m1[i]] 
+1

Realmente no tiene sentido. Preguntaré en el maillist por qué es así. – tillsten

+1

[scipy.org/Cookbook/Indexing](http://scipy.org/Cookbook/Indexing) p. 14 en la indexación booleana multidimensional dice "mira en las herramientas de matriz enmascarada de numpy ... El enfoque obvio no da la respuesta correcta". (Ese documento está bien escrito, necesita actualización.) – denis

+0

@denis, circa 2013 ese documento lo explica bastante bien. Sin embargo, si googlea numpy indexación lógica, el documento que aparece es http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html y no se explica casi tan bien. – John

4

Una alternativa a np.ix_ es convertir las matrices booleanas al número entero matrices (usando np.nonzero()), y luego use np.newaxis para crear arreglos de la forma correcta para aprovechar la transmisión.

import numpy as np 

a=np.random.rand(10,20) 
x_range=np.arange(10) 
y_range=np.arange(20) 

a_tmp=a[x_range<5,:] 
b_correct=a_tmp[:,np.in1d(y_range,[3,4,8])] 

m1=(x_range<5).nonzero()[0] 
m2=np.in1d(y_range,[3,4,8]).nonzero() 
b=a[m1[:,np.newaxis], m2] 
assert np.allclose(b,b_correct) 

b2=a[np.ix_(x_range<5,np.in1d(y_range,[3,4,8]))] 
assert np.allclose(b2,b_correct) 

np.ix_ tiende a ser más lento que el doble indexación. La solución de larga duración parece ser un poco más rápido:

de formato largo:

In [83]: %timeit a[(x_range<5).nonzero()[0][:,np.newaxis], (np.in1d(y_range,[3,4,8])).nonzero()[0]] 
10000 loops, best of 3: 131 us per loop 

doble indexación:

In [85]: %timeit a[x_range<5,:][:,np.in1d(y_range,[3,4,8])] 
10000 loops, best of 3: 144 us per loop 

usando np.ix_:

In [84]: %timeit a[np.ix_(x_range<5,np.in1d(y_range,[3,4,8]))] 
10000 loops, best of 3: 160 us per loop 

Nota: Sería una buena idea probar estos tiempos en su máquina ya que las clasificaciones pueden cambiar dependiendo de su versión de Python, numpy o hardware.

Cuestiones relacionadas