Entendiendo numpy.where

Oct 19 2020

Quiero obtener el primer índice de un elemento de matriz numpy que sea mayor que algún elemento específico de esa misma matriz. Intenté seguir:

>>> Q5=[[1,2,3],[4,5,6]]
>>> Q5 = np.array(Q5)
>>> Q5[0][Q5>Q5[0,0]]
array([2, 3])
>>> np.where(Q5[0]>Q5[0,0])
(array([1, 2], dtype=int32),)
>>> np.where(Q5[0]>Q5[0,0])[0][0]
1

Q1. ¿Es la forma correcta anterior de obtener el primer índice de un elemento en Q5[0]mayor que Q5[0,0]?

Me preocupa más np.where(Q5[0]>Q5[0,0])devolver la tupla (array([1, 2], dtype=int32),)y, por lo tanto, requerir que doble el índice [0][0]al final de np.where(Q5[0]>Q5[0,0])[0][0].

Q2. ¿Por qué esta tupla de retorno, pero a continuación, devuelve la matriz numérica adecuada?

>>> np.where(Q5[0]>Q5[0,0],Q5[0],-1)
array([-1,  2,  3])

Para que pueda indexar directamente:

>>> np.where(Q5[0]>Q5[0,0],Q5[0],-1)[1]
2

Respuestas

hpaulj Oct 19 2020 at 21:42
In [58]: A = np.arange(1,10).reshape(3,3)
In [59]: A.shape
Out[59]: (3, 3)
In [60]: A
Out[60]: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

np.wherecon solo la condición es realmente np.nonzero.

Genere una matriz booleana:

In [63]: A==6
Out[63]: 
array([[False, False, False],
       [False, False,  True],
       [False, False, False]])

Encuentra dónde eso es cierto:

In [64]: np.nonzero(A==6)
Out[64]: (array([1]), array([2]))

El resultado es una tupla, un elemento por dimensión de la condición. Cada elemento es una matriz de indexación, juntos definen la ubicación de los Verdaderos

Otra prueba con varios True

In [65]: (A%3)==1
Out[65]: 
array([[ True, False, False],
       [ True, False, False],
       [ True, False, False]])
In [66]: np.nonzero((A%3)==1)
Out[66]: (array([0, 1, 2]), array([0, 0, 0]))

Usando la tupla para indexar la matriz original:

In [67]: A[np.nonzero((A%3)==1)]
Out[67]: array([1, 4, 7])

Usando el argumento 3 wherepara crear una nueva matriz con una combinación de valores de AyA+10

In [68]: np.where((A%3)==1,A+10, A)
Out[68]: 
array([[11,  2,  3],
       [14,  5,  6],
       [17,  8,  9]])

Si la condición tiene múltiples Verdaderos, nonzerono es la herramienta de prueba para encontrar el "primero", ya que necesariamente encuentra todos.

La tupla distinta de cero se puede convertir en una matriz 2d con a transpose. De hecho, puede ser más fácil obtener el "primero" de esta matriz:

In [73]: np.argwhere((A%3)==1)
Out[73]: 
array([[0, 0],
       [1, 0],
       [2, 0]])

Estás mirando en una matriz 1d, una fila de A:

In [77]: A[0]>A[0,0]
Out[77]: array([False,  True,  True])
In [78]: np.nonzero(A[0]>A[0,0])
Out[78]: (array([1, 2]),)            # 1 element tuple
In [79]: np.argwhere(A[0]>A[0,0])
Out[79]: 
array([[1],
       [2]])
In [81]: np.where(A[0]>A[0,0], 100, 0)     # 3 argument where
Out[81]: array([  0, 100, 100])

Entonces, ya sea que esté buscando una matriz 1d o 2d (o 3 o 4), nonzerodevuelve una tupla con un elemento de matriz por dimensión. De esa manera, siempre se puede usar para indexar una matriz de tamaño similar. La tupla 1d puede parecer redundante, pero es coherente con otros resultados dimensionales.

Cuando intente comprender operaciones como esta, lea los documentos detenidamente y observe los pasos individuales. Aquí miro la matriz condicional, el nonzeroresultado y sus diversos usos.

AsafH Oct 19 2020 at 22:05

numpy.where () es como un bucle for con un if.

numpy.where(condition, values, new_value)

condición - como si condiciones.
valores - Los valores para iterar en
new_value - si la condición es verdadera para un valor , va a cambiar al new_value


Si quisiéramos escribirlo para una matriz unidimensional, debería verse así:
[xv if c else yv 
for c, xv, yv in zip(condition, x, y)]

Ejemplo:

>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.where(a < 5, a, 10*a)
array([ 0,  1,  2,  3,  4, 50, 60, 70, 80, 90])

Primero creamos una matriz con números del 0 al 9 (0, 1, 2 ... 7, 8, 9)
y luego comprobamos todos los valores de la matriz que son mayores de 5 y multiplicamos su valor por 10.
Así que ahora todos los valores de la matriz que son menores que 5 permanecen iguales y todos los valores que son mayores se multiplican por 10

wwii Oct 19 2020 at 21:41

Usar argmaxcon una matriz booleana le dará el índice del primer True.

In [54]: q
Out[54]: 
array([[1, 2, 3],
       [4, 5, 6]])

In [55]: q > q[0,0]
Out[55]: 
array([[False,  True,  True],
       [ True,  True,  True]], dtype=bool)

argmax puede tomar un argumento de eje / dimensión.

In [56]: np.argmax(q > q[0,0], 0)
Out[56]: array([1, 0, 0], dtype=int64)

Eso dice que el primer Verdadero es el índice uno para la columna cero y el índice cero para las columnas uno y dos.

In [57]: np.argmax(q > q[0,0], 1)
Out[57]: array([1, 0], dtype=int64)

Eso dice que el primer Verdadero es el índice uno para la fila cero y el índice cero para la fila uno.


Q1. ¿Es la forma correcta anterior de obtener el primer índice de un elemento en Q5 [0] mayor que Q5 [0,0]?

No, usaría argmaxcon 1para el axisargumento y luego seleccionaría el primer elemento de ese resultado.

Q2. Por qué esta tupla de retorno

Le dijo que regresara -1para valores falsos y devuelva Q5[0]elementos para valores verdaderos.

Q2 ... pero a continuación, ¿devuelve la matriz numérica adecuada?

Tuviste suerte y elegiste el índice correcto.