La salida de numpy.where (condición) no es una matriz, sino una tupla de matrices: ¿por qué?

Estoy experimentando con la función numpy.where(condition[, x, y]) .
De la documentación de números, me entero de que si solo da una matriz como entrada, debería devolver los índices en los que la matriz no es cero (es decir, “Verdadero”):

Si solo se da una condición, devuelve la tupla condition.nonzero (), los índices donde condición es verdadera.

Pero si lo intenta, me devuelve una tupla de dos elementos, donde el primero es la lista de índices deseados y el segundo es un elemento nulo:

 >>> import numpy as np >>> array = np.array([1,2,3,4,5,6,7,8,9]) >>> np.where(array>4) (array([4, 5, 6, 7, 8]),) # notice the comma before the last parenthesis 

Entonces la pregunta es: ¿por qué? ¿Cuál es el propósito de este comportamiento? ¿En qué situación esto es útil? De hecho, para obtener la lista deseada de índices tengo que agregar la indexación, como en np.where(array>4)[0] , que parece … “feo”.


APÉNDICE

Entiendo (de algunas respuestas) que en realidad es una tupla de un solo elemento. Todavía no entiendo por qué dar la salida de esta manera. Para ilustrar cómo esto no es ideal, considere el siguiente error (que motivó mi pregunta en primer lugar):

 >>> import numpy as np >>> array = np.array([1,2,3,4,5,6,7,8,9]) >>> pippo = np.where(array>4) >>> pippo + 1 Traceback (most recent call last): File "", line 1, in  TypeError: can only concatenate tuple (not "int") to tuple 

de modo que necesita hacer un poco de indexación para acceder a la matriz real de índices:

 >>> pippo[0] + 1 array([5, 6, 7, 8, 9]) 

En Python (1) significa solo 1 . () se puede agregar libremente a números de grupo y expresiones para facilitar la lectura humana (por ejemplo, (1+3)*3 v (1+3,)*3 ). Por lo tanto, para denotar una tupla de 1 elemento, usa (1,) (y requiere que usted también la use).

Así

 (array([4, 5, 6, 7, 8]),) 

es una tupla de un elemento, ese elemento es una matriz.

Si aplicó where a una matriz 2d, el resultado sería una tupla de 2 elementos.

El resultado de where es tal que se puede conectar directamente a una ranura de indexación, por ejemplo,

 a[where(a>0)] a[a>0] 

debe devolver las mismas cosas

como lo haría

 I,J = where(a>0) # a is 2d a[I,J] a[(I,J)] 

O con tu ejemplo:

 In [278]: a=np.array([1,2,3,4,5,6,7,8,9]) In [279]: np.where(a>4) Out[279]: (array([4, 5, 6, 7, 8], dtype=int32),) # tuple In [280]: a[np.where(a>4)] Out[280]: array([5, 6, 7, 8, 9]) In [281]: I=np.where(a>4) In [282]: I Out[282]: (array([4, 5, 6, 7, 8], dtype=int32),) In [283]: a[I] Out[283]: array([5, 6, 7, 8, 9]) In [286]: i, = np.where(a>4) # note the , on LHS In [287]: i Out[287]: array([4, 5, 6, 7, 8], dtype=int32) # not tuple In [288]: a[i] Out[288]: array([5, 6, 7, 8, 9]) In [289]: a[(i,)] Out[289]: array([5, 6, 7, 8, 9]) 

======================

np.flatnonzero muestra la forma correcta de devolver solo una matriz, independientemente de las dimensiones de la matriz de entrada.

 In [299]: np.flatnonzero(a>4) Out[299]: array([4, 5, 6, 7, 8], dtype=int32) In [300]: np.flatnonzero(a>4)+10 Out[300]: array([14, 15, 16, 17, 18], dtype=int32) 

Es doc dice:

Esto es equivalente a a.ravel (). Nonzero () [0]

De hecho eso es, literalmente, lo que hace la función.

Al aplanar a elimina la pregunta de qué hacer con múltiples dimensiones. Y luego elimina la respuesta de la tupla, lo que le da una matriz simple. Con el aplanamiento no tiene un estuche especial para arreglos 1d.

===========================

@Divakar sugiere np.argwhere :

 In [303]: np.argwhere(a>4) Out[303]: array([[4], [5], [6], [7], [8]], dtype=int32) 

que hace np.transpose(np.where(a>4))

O si no te gusta el vector de columna, puedes transponerlo de nuevo

 In [307]: np.argwhere(a>4).T Out[307]: array([[4, 5, 6, 7, 8]], dtype=int32) 

Excepto que ahora es una matriz 1xn.

Podríamos haber envuelto where en array :

 In [311]: np.array(np.where(a>4)) Out[311]: array([[4, 5, 6, 7, 8]], dtype=int32) 

Hay muchas maneras de sacar una matriz de la tupla where ( [0] , i,= , transpose , array , etc.).

Respuesta corta: np.where está diseñado para tener un resultado consistente independientemente de la dimensión de la matriz.

Una matriz bidimensional tiene dos índices, por lo que el resultado de np.where es una tupla de longitud 2 que contiene los índices relevantes. Esto generaliza a una tupla de longitud 3 para 3 dimensiones, una tupla de longitud 4 para 4 dimensiones o una tupla de longitud N para N dimensiones. Por esta regla, está claro que en 1 dimensión, el resultado debe ser una tupla de longitud 1.

Solo usa la función np.asarray . En tu caso:

 >>> import numpy as np >>> array = np.array([1,2,3,4,5,6,7,8,9]) >>> pippo = np.asarray(np.where(array>4)) >>> pippo + 1 array([[5, 6, 7, 8, 9]])