2013-05-02 19 views
63

Ho una serie di distanze chiamate dist. Voglio selezionare dist che sono tra due valori. Ho scritto la seguente riga di codice per farlo:Numpy in cui sono presenti più condizioni

dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))] 

Tuttavia questo seleziona solo per la condizione

(np.where(dists <= r + dr)) 

Se faccio i comandi in modo sequenziale utilizzando una variabile temporanea funziona benissimo. Perché il codice sopra non funziona e come posso farlo funzionare?

Acclamazioni

risposta

107

Il modo migliore in vostro caso particolare sarebbe solo cambiare i vostri due criteri a un criterio:

dists[abs(dists - r - dr/2.) <= dr/2.] 

Si crea solo un array booleano, e, a mio parere è più facile leggere perché dice, è dist all'interno di un dr o r? (Anche se ridefinire il r come il centro della regione di interesse anziché l'inizio, quindi r = r + dr/2.) Ma questo non risponde alla tua domanda.


La risposta alla tua domanda:
In realtà non c'è bisogno where se si sta solo cercando di filtrare gli elementi di dists che non si adattano ai tuoi criteri:

dists[(dists >= r) & (dists <= r+dr)] 

Perché il & ti darà un elementwise and (le parentesi sono necessarie).

Oppure, se si vuole utilizzare where per qualche motivo, si può fare:

dists[(np.where((dists >= r) & (dists <= r + dr)))] 

Perché:
Il motivo per cui non funziona è perché np.where restituisce una lista di indici, non un array booleano. Stai cercando di ottenere and tra due elenchi di numeri, che ovviamente non hanno i valori True/False che ti aspetti. Se a e b sono entrambi valori True, quindi a and b restituisce b. Quindi dire qualcosa come [0,1,2] and [2,3,4] ti darà solo [2,3,4].Eccolo in azione:

In [230]: dists = np.arange(0,10,.5) 
In [231]: r = 5 
In [232]: dr = 1 

In [233]: np.where(dists >= r) 
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),) 

In [234]: np.where(dists <= r+dr) 
Out[234]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),) 

In [235]: np.where(dists >= r) and np.where(dists <= r+dr) 
Out[235]: (array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),) 

Cosa ti aspettavi per confrontare era semplicemente l'array booleano, ad esempio

In [236]: dists >= r 
Out[236]: 
array([False, False, False, False, False, False, False, False, False, 
     False, True, True, True, True, True, True, True, True, 
     True, True], dtype=bool) 

In [237]: dists <= r + dr 
Out[237]: 
array([ True, True, True, True, True, True, True, True, True, 
     True, True, True, True, False, False, False, False, False, 
     False, False], dtype=bool) 

In [238]: (dists >= r) & (dists <= r + dr) 
Out[238]: 
array([False, False, False, False, False, False, False, False, False, 
     False, True, True, True, False, False, False, False, False, 
     False, False], dtype=bool) 

Ora è possibile chiamare np.where sulla matrice booleana combinato:

In [239]: np.where((dists >= r) & (dists <= r + dr)) 
Out[239]: (array([10, 11, 12]),) 

In [240]: dists[np.where((dists >= r) & (dists <= r + dr))] 
Out[240]: array([ 5. , 5.5, 6. ]) 

O semplicemente indicizzare l'array originale con l'array booleano utilizzando fancy indexing

In [241]: dists[(dists >= r) & (dists <= r + dr)] 
Out[241]: array([ 5. , 5.5, 6. ]) 
0

Ho risolto questo semplice esempio

import numpy as np 

ar = np.array([3,4,5,14,2,4,3,7]) 

print [X for X in list(ar) if (X >= 3 and X <= 6)] 

>>> 
[3, 4, 5, 4, 3] 
+5

In questo caso non è necessario eseguire iterazioni. NumPy ha l'indicizzazione booleana. – M456

2

Prova:

np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0]) 
16

Dato che la risposta accettata spiegato il problema molto bene. è anche possibile utilizzare numpy logical functions, che è più adatto qui per le condizioni multiple:

np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr))) 
+2

Questo IMO è la risposta più leggibile! –

+1

manca un ')' alla fine però giusto? – Olivia

+1

@ Olivia Sì, grazie per avermelo ricordato;) – Kasramvd

0

Mi piace usare np.vectorize per questi compiti. Si consideri il seguente:

>>> # function which returns True when constraints are satisfied. 
>>> func = lambda d: d >= r and d<= (r+dr) 
>>> 
>>> # Apply constraints element-wise to the dists array. 
>>> result = np.vectorize(func)(dists) 
>>> 
>>> result = np.where(result) # Get output. 

È anche possibile utilizzare np.argwhere invece di np.where per l'uscita chiara. Ma questa è la tua chiamata :)

Spero che sia d'aiuto.

Problemi correlati