2013-05-02 16 views
63

Ich habe eine Reihe von Distanzen genannt dists. Ich möchte Distanzen auswählen, die zwischen zwei Werten liegen. Ich schrieb die folgende Zeile Code, das zu tun:Numpy, wo Funktion mehrere Bedingungen

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

jedoch dies nur für die Bedingung wählt

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

Wenn ich die Befehle nacheinander tun, indem Sie eine temporäre Variable es funktioniert gut. Warum funktioniert der obige Code nicht und wie bekomme ich ihn zum Laufen?

Prost

Antwort

107

Der beste Weg, in Ihrem speziellen Fall würde nur Ihre zwei Kriterien ein Kriterium zu ändern sein:

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

Es schafft nur ein boolean-Array, und meiner Meinung nach ist einfacher zu lesen, weil es sagt, ist dist innerhalb einer dr oder r? (Obwohl ich r definieren würde, um das Zentrum Ihrer Region von Interesse statt des Anfangs zu sein, also r = r + dr/2.) Aber das beantwortet Ihre Frage nicht.


Die Antwort auf Ihre Frage:
Sie eigentlich nicht where brauchen, wenn Sie nur versuchen, die Elemente von dists, um herauszufiltern, die nicht Ihren Kriterien passen:

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

Weil die & Ihnen eine elementweise and geben wird (die Klammern sind notwendig).

Oder, wenn Sie where aus irgendeinem Grund verwenden möchten, können Sie tun:

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

Warum:
Der Grund es nicht funktioniert, weil np.where eine Liste zurückgibt von Indizes, kein boolesches Array. Sie versuchen, and zwischen zwei Listen von Zahlen zu bekommen, die natürlich nicht die Werte haben, die Sie erwarten. Wenn a und b beide True Werte sind, dann gibt a and bb zurück. So etwas zu sagen wie [0,1,2] and [2,3,4] wird nur [2,3,4] geben.Hier ist es in Aktion:

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

Was Sie erwartet hatten war einfach die boolean-Array zu vergleichen, zum Beispiel

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) 

Jetzt können Sie np.where auf den kombinierten boolean Array nennen:

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

Oder indizieren Sie einfach das ursprüngliche Array mit dem booleschen Array unter Verwendung von fancy indexing

0

Ich habe dieses einfache Beispiel ausgearbeitet

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 diesem Fall muss nicht iteriert werden. NumPy hat boolesche Indizierung. – M456

2

Versuche:

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

Da die akzeptierte Antwort das Problem sehr gut erklärt. Sie können auch numpy logical functions verwenden, die hier für mehrere Zustand besser geeignet ist:

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

Diese IMO ist die beste Antwort! –

+1

fehlt ein ')' am Ende obwohl richtig? – Olivia

+1

@Olivia Ja, danke für die Erinnerung;) – Kasramvd

0

Ich mag np.vectorize für solche Aufgaben verwenden. Beachten Sie Folgendes:

>>> # 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. 

Sie auch np.argwhere statt np.where für klaren Ausgang verwenden können. Aber das ist dein Ruf :)

Hoffe es hilft.