Numpy ที่ทำหน้าที่หลายเงื่อนไข


132

ฉันมีระยะทางที่เรียกว่าระยะทาง ฉันต้องการเลือก dists ซึ่งอยู่ระหว่างสองค่า ฉันเขียนบรรทัดของรหัสต่อไปนี้เพื่อทำ:

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

อย่างไรก็ตามสิ่งนี้จะเลือกสำหรับเงื่อนไขเท่านั้น

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

ถ้าฉันทำคำสั่งตามลำดับโดยใช้ตัวแปรชั่วคราวมันทำงานได้ดี ทำไมรหัสด้านบนใช้งานไม่ได้และฉันจะทำให้มันทำงานได้อย่างไร

ไชโย

คำตอบ:


203

วิธีที่ดีที่สุดในกรณีของคุณคือเปลี่ยนเกณฑ์ทั้งสองเป็นเกณฑ์เดียว:

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

มันเพียง แต่จะสร้างอาร์เรย์แบบบูลและในความคิดของฉันคือง่ายต่อการอ่านเพราะมันบอกว่าเป็นdistภายในdrหรือr? (แม้ว่าฉันจะนิยามใหม่rให้เป็นศูนย์กลางของภูมิภาคที่คุณสนใจแทนจุดเริ่มต้นดังนั้นr = r + dr/2.) แต่นั่นไม่ได้ตอบคำถามของคุณ


คำตอบสำหรับคำถามของคุณ:
คุณไม่จำเป็นจริง ๆwhereถ้าคุณแค่พยายามที่จะกรององค์ประกอบdistsที่ไม่ตรงกับเกณฑ์ของคุณ:

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

เพราะ&จะทำให้คุณมีองค์ประกอบตามลำดับand(จำเป็นต้องใส่วงเล็บ)

หรือถ้าคุณต้องการใช้whereด้วยเหตุผลบางอย่างคุณสามารถทำได้:

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

ทำไม:
เหตุผลที่มันใช้ไม่ได้เพราะnp.whereคืนค่ารายการดัชนีไม่ใช่อาเรย์บูลีน คุณกำลังพยายามหาandตัวเลขสองรายการซึ่งแน่นอนว่าไม่มีTrue/ Falseค่าที่คุณคาดหวัง ถ้าaและbมีทั้งTrueค่าแล้วผลตอบแทนa and b bดังนั้นพูดอะไรบางอย่างเช่นเพียงแค่จะทำให้คุณ[0,1,2] and [2,3,4] [2,3,4]นี่คือการกระทำ:

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

สิ่งที่คุณคาดหวังว่าจะเปรียบเทียบเป็นเพียงตัวอย่างของบูลีน

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)

ตอนนี้คุณสามารถโทรหาnp.whereอาร์เรย์บูลีนที่รวมกัน:

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

หรือทำดัชนีอาร์เรย์เดิมด้วยอาร์เรย์บูลีนโดยใช้การทำดัชนีแฟนซี

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

61

คำตอบที่ยอมรับอธิบายปัญหาได้ดีพอ อย่างไรก็ตามวิธีการ Numpythonic มากขึ้นสำหรับการใช้หลายเงื่อนไขคือการใช้ฟังก์ชั่นตรรกะ numpy ใน ase นี้คุณสามารถใช้np.logical_and:

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

11

สิ่งหนึ่งที่น่าสนใจที่นี่ วิธีปกติในการใช้ORและและก็จะใช้งานได้ในกรณีนี้ แต่มีการเปลี่ยนแปลงเล็กน้อย แทนที่จะเป็น "และ" และแทนที่จะเป็น "หรือ" ให้ใช้เครื่องหมายและ (&)และตัวดำเนินการไปป์ (|)และจะใช้งานได้

เมื่อเราใช้'และ' :

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

เมื่อเราใช้เครื่องหมาย & (&) :

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

และนี่ก็เหมือนกันในกรณีที่เราพยายามที่จะใช้ตัวกรองหลายตัวในกรณีของดาต้าดาต้าแพนด้า ตอนนี้เหตุผลที่ต้องทำบางอย่างกับ Logical Operators และ Bitwise Operator และเพื่อความเข้าใจที่มากขึ้นเกี่ยวกับสิ่งเดียวกันฉันแนะนำให้ทำตามคำตอบนี้หรือ Q / A ที่คล้ายกันใน stackoverflow

UPDATE

ผู้ใช้ถามว่าทำไมจึงมีความจำเป็นในการให้ (ar> 3) และ (ar <6) ภายในวงเล็บ นี่คือสิ่งที่ ก่อนที่ฉันจะเริ่มพูดคุยเกี่ยวกับสิ่งที่เกิดขึ้นที่นี่เราจำเป็นต้องรู้เกี่ยวกับความสำคัญของโอเปอเรเตอร์ใน Python

คล้ายกับสิ่งที่ BODMAS กำลังพูดถึง Python ให้ความสำคัญกับสิ่งที่ควรปฏิบัติก่อน รายการภายในวงเล็บจะถูกดำเนินการก่อนจากนั้นผู้ปฏิบัติงานระดับบิตจะทำงาน ฉันจะแสดงสิ่งที่เกิดขึ้นในทั้งสองกรณีด้านล่างเมื่อคุณใช้และไม่ใช้ "(", ")"

case1:

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)

เนื่องจากไม่มีเครื่องหมายวงเล็บอยู่ที่นี่ตัวดำเนินการบิต ( &) กำลังสับสนที่นี่ว่าสิ่งที่คุณถามเพื่อรับตรรกะและของเพราะในตารางที่มีความสำคัญผู้ประกอบการถ้าคุณเห็น&จะได้รับความสำคัญกว่า<หรือ>ผู้ประกอบการ นี่คือตารางจากลำดับความสำคัญต่ำสุดไปถึงลำดับสูงสุด

ป้อนคำอธิบายรูปภาพที่นี่

มันไม่ได้ทำการแสดง<และ>การดำเนินการและถูกขอให้ดำเนินการทางตรรกะและการดำเนินการ นั่นคือสาเหตุที่ทำให้เกิดข้อผิดพลาดนั้น

หนึ่งสามารถตรวจสอบลิงค์ต่อไปนี้เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับ: ความสำคัญของผู้ประกอบการ

ตอนนี้ถึงกรณีที่ 2:

หากคุณใช้ตัวยึดคุณจะเห็นได้ชัดเจนว่าเกิดอะไรขึ้น

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)

สองอาร์เรย์ของจริงและเท็จ และคุณสามารถดำเนินการตรรกะและการดำเนินการกับพวกเขาได้อย่างง่ายดาย ซึ่งให้คุณ:

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

และที่เหลือคุณจะรู้ว่า np.where สำหรับกรณีที่กำหนดไม่ว่าจะเป็น True จะกำหนดค่าแรก (เช่นที่นี่ 'โย่') และหากเป็นเท็จอีกอัน (เช่นที่นี่จะรักษาต้นฉบับ)

นั่นคือทั้งหมดที่ ฉันหวังว่าฉันจะอธิบายคำถามได้ดี


1
ทำไมคุณต้องใส่()รอบ(ar>3)และ(ar>6)?
RTrain3k

นั่นเป็นคำถามที่ดีจริงๆ เป็นคำถามที่ดีที่ฉันต้องคิดเองว่าสิ่งใดในโลกนี้ที่ต้องการ ดังนั้นฉันก็ถามเพื่อนร่วมงานด้วยและเราก็คุยกันตอนนี้ฉันมีทางออกให้คุณแล้ว วางไว้ในคำตอบในรูปแบบ UPDATE มันง่ายจริงๆ แต่เป็นเรื่องยากที่จะเข้าใจจริงๆ
Amit Amola

ชำระเงินอัปเดต RTrain3k ฉันได้ตอบคำถามของคุณแล้ว
Amit Amola

5

ฉันชอบที่จะใช้np.vectorizeสำหรับงานดังกล่าว พิจารณาสิ่งต่อไปนี้:

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

คุณยังสามารถใช้np.argwhereแทนnp.whereเอาต์พุตที่ชัดเจนได้ แต่นั่นคือสายของคุณ :)

หวังว่ามันจะช่วย



2

สิ่งนี้น่าจะใช้ได้:

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

วิธีที่หรูหราที่สุด ~~



0

ฉันทำตัวอย่างง่ายๆนี้แล้ว

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]

6
ไม่จำเป็นต้องทำซ้ำในกรณีนี้ NumPy มีการทำดัชนีบูลีน
M456
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.