Come seleziono gli elementi di una determinata condizione di array?


156

Supponiamo di avere una matrice NumPy x = [5, 2, 3, 1, 4, 5], y = ['f', 'o', 'o', 'b', 'a', 'r']. Voglio selezionare gli elementi in ycorrispondenza degli elementi xche sono maggiori di 1 e minori di 5.

Provai

x = array([5, 2, 3, 1, 4, 5])
y = array(['f','o','o','b','a','r'])
output = y[x > 1 & x < 5] # desired output is ['o','o','a']

ma questo non funziona. Come lo farei?

Risposte:


220

La tua espressione funziona se aggiungi parentesi:

>>> y[(1 < x) & (x < 5)]
array(['o', 'o', 'a'], 
      dtype='|S1')

1
Che bello .. vecMask = 1 <x genera una maschera vettoriale come vecMask = (False, True, ...), che può essere semplicemente combinata con altre maschere vettoriali. Ogni elemento è la condizione per prendere gli elementi di un vettore sorgente (Vero) o no (Falso). Questo può essere usato anche con la versione completa numpy.extract (vecMask, vecSrc) o numpy.where (vecMask, vecSrc, vecSrc2).
MasterControlProgram

6
@JennyYueJin: succede a causa della precedenza. (Bit a bit) &ha una precedenza più alta di <e >, che a sua volta ha una precedenza più alta di (logica) and. x > 1 and x < 5evoca prima le disuguaglianze e poi la congiunzione logica; x > 1 & x < 5valuta la congiunzione bit a bit di 1e (i valori in) x, quindi le disuguaglianze. (x > 1) & (x < 5)forza le disuguaglianze a valutare per prime, quindi tutte le operazioni avvengono nell'ordine previsto e i risultati sono tutti ben definiti. Vedi i documenti qui.
calavicci,

@ ru111 Funziona anche su Python 3.6 (non c'è motivo per smettere di funzionare).
jfs,

Ottengo "ValueError: il valore di verità di un array con più di un elemento è ambiguo. Usa a.any () o a.all ()"
ru111

@ ru111 dovresti scrivere (0 < x) & (x < 10)(come mostrato nella risposta) invece del 0 < x < 10quale non funziona per gli array numpy su qualsiasi versione di Python.
jfs

34

L'OP IMO in realtà non vuole np.bitwise_and()(aka &) ma in realtà vuole np.logical_and()perché stanno confrontando valori logici come Truee False- vedi questo post SO su logico o bit per vedere la differenza.

>>> x = array([5, 2, 3, 1, 4, 5])
>>> y = array(['f','o','o','b','a','r'])
>>> output = y[np.logical_and(x > 1, x < 5)] # desired output is ['o','o','a']
>>> output
array(['o', 'o', 'a'],
      dtype='|S1')

E un modo equivalente per farlo è quello np.all()di impostare l' axisargomento in modo appropriato.

>>> output = y[np.all([x > 1, x < 5], axis=0)] # desired output is ['o','o','a']
>>> output
array(['o', 'o', 'a'],
      dtype='|S1')

dai numeri:

>>> %timeit (a < b) & (b < c)
The slowest run took 32.97 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 1.15 µs per loop

>>> %timeit np.logical_and(a < b, b < c)
The slowest run took 32.59 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.17 µs per loop

>>> %timeit np.all([a < b, b < c], 0)
The slowest run took 67.47 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 5.06 µs per loop

quindi l'utilizzo np.all()è più lento, ma è più &o logical_andmeno lo stesso.


7
Devi stare un po 'attento a come parli di ciò che viene valutato. Ad esempio, in output = y[np.logical_and(x > 1, x < 5)], x < 5 viene valutato (probabilmente creando un array enorme), anche se è il secondo argomento, poiché tale valutazione avviene al di fuori della funzione. IOW, logical_andvengono passati due argomenti già valutati. Questo è diverso dal solito caso di a and b, in cui bnon viene valutato se aè truelike.
DSM,

15
non c'è differenza tra bitwise_and () e logical_and () per gli array booleani
jfs

22

Aggiungi un dettaglio alle risposte di @JF Sebastian e @Mark Mikofski:
se si desidera ottenere gli indici corrispondenti (anziché i valori effettivi dell'array), farà il seguente codice:

Per soddisfare molteplici (tutte) condizioni:

select_indices = np.where( np.logical_and( x > 1, x < 5) )[0] #   1 < x <5

Per soddisfare più (o) condizioni:

select_indices = np.where( np.logical_or( x < 1, x > 5 ) )[0] # x <1 or x >5

2
Nota che numpy.where non solo restituirà un array di indici, ma restituirà invece una tupla (l'output di condition.nonzero ()) contenente array - in questo caso (the array of indices you want,), quindi dovrai select_indices = np.where(...)[0]ottenere il risultato che desideri e aspettatevi.
calavicci,

5

Mi piace usare np.vectorizeper tali compiti. Considera quanto segue:

>>> # Arrays
>>> x = np.array([5, 2, 3, 1, 4, 5])
>>> y = np.array(['f','o','o','b','a','r'])

>>> # Function containing the constraints
>>> func = np.vectorize(lambda t: t>1 and t<5)

>>> # Call function on x
>>> y[func(x)]
>>> array(['o', 'o', 'a'], dtype='<U1')

Il vantaggio è che puoi aggiungere molti altri tipi di vincoli nella funzione vettoriale.

Spero che sia d'aiuto.


1
Questo non è un buon modo per eseguire l'indicizzazione in NumPy (sarà molto lento).
Alex Riley,

1

In realtà lo farei così:

L1 è la lista indice di elementi che soddisfano la condizione 1; (forse puoi usare somelist.index(condition1)o np.where(condition1)per ottenere L1.)

Allo stesso modo, ottieni L2, un elenco di elementi che soddisfano la condizione 2;

Quindi trovi l'intersezione usando intersect(L1,L2).

È inoltre possibile trovare l'intersezione di più elenchi se si soddisfano più condizioni.

Quindi è possibile applicare l'indice in qualsiasi altro array, ad esempio x.


0

Per gli array 2D, è possibile farlo. Crea una maschera 2D usando la condizione. Digitare la maschera delle condizioni su int o float, a seconda dell'array, e moltiplicarla con l'array originale.

In [8]: arr
Out[8]: 
array([[ 1.,  2.,  3.,  4.,  5.],
       [ 6.,  7.,  8.,  9., 10.]])

In [9]: arr*(arr % 2 == 0).astype(np.int) 
Out[9]: 
array([[ 0.,  2.,  0.,  4.,  0.],
       [ 6.,  0.,  8.,  0., 10.]])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.