Numpy waar functie meerdere voorwaarden

Ik heb een reeks afstanden die dists worden genoemd. Ik wil afstanden selecteren die tussen twee waarden liggen. Ik heb de volgende regel code geschreven om dat te doen:

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

Dit wordt echter alleen geselecteerd voor de voorwaarde

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

Als ik de opdrachten opeenvolgend doe door een tijdelijke variabele te gebruiken, werkt het prima. Waarom werkt bovenstaande code niet en hoe krijg ik deze werkend?

Proost


Antwoord 1, autoriteit 100%

De beste manier in uw specifieke gevalzou zijn om uw twee criteria te veranderen in één criterium:

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

Het creëert slechts één booleaanse array en is naar mijn mening gemakkelijker te lezen omdat er staat: is distbinnen een drof r?(Hoewel ik ropnieuw zou definiëren als het middelpunt van je interessegebied in plaats van het begin, dus r = r + dr/2.) Maar dat is geen antwoord op je vraag.


Het antwoord op uw vraag:
Je hebt whereeigenlijk niet nodig als je alleen de elementen van distsprobeert uit te filteren die niet aan je criteria voldoen:

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

Omdat de &u een elementsgewijs andgeeft (de haakjes zijn nodig).

Of, als je om de een of andere reden wherewilt gebruiken, kun je het volgende doen:

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

Waarom:
De reden dat het niet werkt is omdat np.whereeen lijst met indices retourneert, geen booleaanse array. Je probeert andtussen twee getallenlijsten te krijgen, die natuurlijk niet de True/Falsewaarden hebben die je verwacht. Als aen bbeide Truewaarden zijn, dan retourneert a and bb. Dus als je iets als [0,1,2] and [2,3,4]zegt, krijg je gewoon [2,3,4]. Hier is het in actie:

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

Wat u verwachtte te vergelijken was bijvoorbeeld gewoon de booleaanse array

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)

Nu kun je np.whereaanroepen op de gecombineerde booleaanse array:

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

Of indexeer eenvoudig de originele array met de boolean array met behulp van fancy indexing

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

Antwoord 2, autoriteit 30%

Het geaccepteerde antwoord verklaarde het probleem goed genoeg. De meer Numpythonische benadering voor het toepassen van meerdere voorwaarden is echter het gebruik van numpy logische functies. In dit geval kunt u np.logical_andgebruiken:

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

Antwoord 3, autoriteit 8%

Een interessant ding om hier op te wijzen; de gebruikelijke manier om OFen ANDte gebruiken, zal in dit geval ook werken, maar met een kleine wijziging. Gebruik in plaats van “en” en in plaats van “of” liever Ampersand(&)en Pipe Operator(|)en het zal werken.

Als we ‘en’gebruiken:

ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) and (ar<6), 'yo', ar)
Output:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Als we Ampersand(&)gebruiken:

ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) & (ar<6), 'yo', ar)
Output:
array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')

En dit is hetzelfde in het geval dat we meerdere filters proberen toe te passen in het geval van panda’s Dataframe. De redenering hierachter heeft iets te maken met logische operators en bitsgewijze operators en voor meer begrip hierover raad ik aan om deze door te nemen antwoordof soortgelijke Q/A in stackoverflow.

UPDATE

Een gebruiker vroeg waarom het nodig is om (ar>3) en (ar<6) tussen haakjes te geven. Nou, hier is het ding. Voordat ik begin te praten over wat hier gebeurt, moet men weten wat de prioriteit van de operator is in Python.

Net als waar BODMAS over gaat, geeft python ook voorrang aan wat als eerste moet worden uitgevoerd. Items tussen haakjes worden eerst uitgevoerd en vervolgens komt de bitsgewijze operator aan het werk. Ik zal hieronder laten zien wat er gebeurt in beide gevallen waarin u “(“, “)” wel en niet gebruikt.

Geval1:

np.where( ar>3 & ar<6, 'yo', ar)
np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)

Omdat er hier geen haakjes staan, raakt de bitsgewijze operator (&) hier in de war, wat vraag je het zelfs om logisch AND te krijgen, omdat in de operatorprioriteittabel als je ziet , &krijgt voorrang op de operatoren <of >. Hier is de tabel van de laagste prioriteit tot de hoogste prioriteit.

Het voert niet eens de bewerkingen <en >uit en wordt gevraagd om een logische EN-bewerking uit te voeren. Dus daarom geeft het die fout.

Je kunt de volgende link bekijken voor meer informatie over: operator
voorrang

Nu naar Case 2:

Als je de beugel wel gebruikt, zie je duidelijk wat er gebeurt.

np.where( (ar>3) & (ar<6), 'yo', ar)
np.where( (array([False,  True,  True,  True, False,  True, False,  True])) & (array([ True,  True,  True, False,  True,  True,  True, False])), 'yo', ar)

Twee arrays van True en False. En u kunt er eenvoudig een logische EN-bewerking op uitvoeren. Dat geeft je:

np.where( array([False,  True,  True, False, False,  True, False, False]),  'yo', ar)

En rust, weet je, np.where, voor bepaalde gevallen, waar True, wijst de eerste waarde toe (d.w.z. hier ‘yo’) en als False, de andere (d.w.z. hier, het origineel behouden).

Dat is alles. Ik hoop dat ik de vraag goed heb uitgelegd.


Antwoord 4, autoriteit 2%

Ik gebruik graag np.vectorizevoor dergelijke taken. Overweeg het volgende:

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

Je kunt ook np.argwheregebruiken in plaats van np.wherevoor duidelijke uitvoer.


Antwoord 5

Probeer:

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

Antwoord 6

Probeer:

import numpy as np
dist = np.array([1,2,3,4,5])
r = 2
dr = 3
np.where(np.logical_and(dist> r, dist<=r+dr))

Uitvoer: (array([2, 3]),)

Je kunt Logische functieszien voor meer details.


Antwoord 7

Dit zou moeten werken:

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

Antwoord 8

Ik heb dit eenvoudige voorbeeld uitgewerkt

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]

Other episodes