Capire numpy.where

Oct 19 2020

Voglio ottenere il primo indice dell'elemento dell'array numpy che è maggiore di un elemento specifico dello stesso array. Ho provato a seguire:

>>> 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. Il modo sopra è corretto per ottenere il primo indice di un elemento in Q5[0]maggiore di Q5[0,0]?

Mi interessa di più np.where(Q5[0]>Q5[0,0])restituire la tupla (array([1, 2], dtype=int32),)e quindi richiedermi di raddoppiare l'indice [0][0]alla fine di np.where(Q5[0]>Q5[0,0])[0][0].

Q2. Perché questa tupla di ritorno, ma di seguito restituisce il corretto array numpy?

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

In modo che io possa indicizzare direttamente:

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

Risposte

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 condizione è davvero np.nonzero.

Genera un array booleano:

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

Trova dove è vero:

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

Il risultato è una tupla, un elemento per dimensione della condizione. Ogni elemento è un array di indicizzazione, insieme definiscono la posizione dei True

Un altro test con diversi 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]))

Utilizzando la tupla per indicizzare l'array originale:

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

Utilizzando l'argomento 3 whereper creare un nuovo array con una combinazione di valori da AeA+10

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

Se la condizione ha più True, nonzeronon è lo strumento di test per trovare il "primo", poiché trova necessariamente tutto.

La tupla diversa da zero può essere trasformata in un array 2d con estensione transpose. In realtà potrebbe essere più semplice ottenere il "primo" da questo array:

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

Stai cercando in un array 1d, una riga di 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])

Quindi, se stai cercando un array 1d o 2d (o 3 o 4), nonzerorestituisce una tupla con un elemento array per dimensione. In questo modo può sempre essere utilizzato per indicizzare un array di dimensioni simili. La tupla 1d potrebbe sembrare ridondante, ma è coerente con altri risultati dimensionali.

Quando si cerca di comprendere operazioni come questa, leggere attentamente i documenti e osservare i singoli passaggi. Qui guardo la matrice condizionale, il nonzerorisultato e i suoi vari usi.

AsafH Oct 19 2020 at 22:05

numpy.where () è come un ciclo for con un if.

numpy.where(condition, values, new_value)

condizione - proprio come se le condizioni.
valori - I valori da iterare su
new_value - se la condizione è vera per un valore , cambierà in new_value


Se vorremmo scriverlo per un array unidimensionale dovrebbe assomigliare a questo:
[xv if c else yv 
for c, xv, yv in zip(condition, x, y)]

Esempio:

>>> 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])

Per prima cosa creiamo un array con numeri da 0 a 9 (0, 1, 2 ... 7, 8, 9)
e poi controlliamo tutti i valori dell'array che sono maggiori di 5 e moltiplichiamo il loro valore per 10.
Quindi ora tutti i valori nella matrice inferiori a 5 sono rimasti gli stessi e tutti i valori maggiori sono stati moltiplicati per 10

wwii Oct 19 2020 at 21:41

L'utilizzo argmaxcon un array booleano ti darà l'indice del primo 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 può accettare un argomento asse / dimensione.

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

Questo dice che il primo True è l'indice uno per la colonna zero e l'indice zero per le colonne uno e due.

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

Questo dice che il primo True è l'indice uno per la riga zero e l'indice zero per la riga uno.


Q1. Il modo sopra è corretto per ottenere il primo indice di un elemento in Q5 [0] maggiore di Q5 [0,0]?

No, userei argmaxcon 1per l' axisargomento, quindi selezionerei il primo elemento da quel risultato.

Q2. Perché questa tupla di ritorno

Gli hai detto di restituire -1per valori False e restituire Q5[0]articoli per valori True.

Q2 ... ma di seguito restituisce un array numpy corretto?

Sei stato fortunato e hai scelto l'indice corretto.