ฉันจะเลือกองค์ประกอบของอาร์เรย์ที่กำหนดเงื่อนไขได้อย่างไร


156

สมมติว่าฉันมีอาเรx = [5, 2, 3, 1, 4, 5]ย์y = ['f', 'o', 'o', 'b', 'a', 'r']มากมาย ฉันต้องการเลือกองค์ประกอบที่yสอดคล้องกับองค์ประกอบxที่มากกว่า 1 และน้อยกว่า 5

ฉันเหนื่อย

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

แต่มันใช้งานไม่ได้ ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


220

นิพจน์ของคุณใช้งานได้หากคุณเพิ่มวงเล็บ:

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

1
นั่นเป็นสิ่งที่ดี .. vecMask = 1 <x สร้างเวกเตอร์มาสก์เช่น vecMask = (False, True, ... ) ซึ่งสามารถนำมารวมกับเวกเตอร์มาสก์อื่น ๆ ได้ แต่ละองค์ประกอบเป็นเงื่อนไขในการรับองค์ประกอบของเวกเตอร์แหล่งที่มา (จริง) หรือไม่ (เท็จ) สามารถใช้กับเวอร์ชันเต็ม numpy.extract (vecMask, vecSrc) หรือ numpy.where (vecMask, vecSrc, vecSrc2)
MasterControlProgram

6
@JennyYueJin: มันเกิดขึ้นเพราะความสำคัญ (Bitwise) &มีความสำคัญสูงกว่า<และ>ซึ่งจะมีความสำคัญสูงกว่า and(ตรรกะ) x > 1 and x < 5หลีกเลี่ยงความไม่เท่าเทียมกันก่อนแล้วจึงรวมตรรกะ; x > 1 & x < 5ประเมินการรวมกันในระดับบิตของ1และ (ค่าใน) xจากนั้นความไม่เท่าเทียมกัน (x > 1) & (x < 5)บังคับให้ความไม่เท่าเทียมกันประเมินผลก่อนดังนั้นการดำเนินการทั้งหมดจะเกิดขึ้นตามลำดับที่ตั้งใจไว้และผลลัพธ์นั้นถูกกำหนดไว้อย่างดี ดูเอกสารที่นี่
calavicci

@ ru111 มันใช้ได้กับ Python 3.6 ด้วย (ไม่มีเหตุผลอะไรที่จะหยุดทำงาน)
jfs

ฉันได้รับ "ValueError: ค่าความจริงของอาร์เรย์ที่มีองค์ประกอบมากกว่าหนึ่งรายการคลุมเครือใช้ a.any () หรือ a.all ()"
ru111

@ ru111 คุณควรเขียน(0 < x) & (x < 10)(ดังที่แสดงในคำตอบ) แทนที่จะใช้0 < x < 10ไม่ได้กับอาร์เรย์ numpy ใน Python เวอร์ชั่นใด ๆ
jfs

34

IMO OP ไม่ต้องการจริง ๆnp.bitwise_and()(aka &)แต่ต้องการnp.logical_and()เพราะพวกเขากำลังเปรียบเทียบค่าตรรกะเช่นTrueและFalse- ดูโพสต์ SO นี้บนตรรกะเทียบกับบิตเพื่อดูความแตกต่าง

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

และวิธีที่เท่าเทียมกันในการทำเช่นนี้คือด้วยnp.all()การตั้งค่าaxisอาร์กิวเมนต์อย่างเหมาะสม

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

โดยตัวเลข:

>>> %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

ดังนั้นการใช้np.all()จะช้ากว่า&และlogical_andมีความใกล้เคียงกัน


7
คุณต้องระวังนิดหน่อยเกี่ยวกับวิธีที่คุณพูดเกี่ยวกับสิ่งที่ประเมิน ยกตัวอย่างเช่นในoutput = y[np.logical_and(x > 1, x < 5)], x < 5 มีการประเมินผล (อาจจะสร้างอาร์เรย์มหาศาล) แม้ว่าจะเป็นอาร์กิวเมนต์ที่สองเพราะการประเมินผลที่เกิดขึ้นด้านนอกของฟังก์ชั่น IOW logical_andได้รับข้อโต้แย้งที่ผ่านการประเมินแล้วสองข้อ สิ่งนี้แตกต่างจากกรณีปกติa and bที่bไม่ได้รับการประเมินว่าaเป็น truelike
DSM

15
ไม่มีความแตกต่างระหว่าง bitwise_and () และ logical_and () สำหรับอาร์เรย์แบบบูล
jfs

21

เพิ่มรายละเอียดหนึ่งคำตอบให้กับ @JF Sebastian และ @Mark Mikofski:
หากต้องการรับดัชนีที่เกี่ยวข้อง (แทนที่จะเป็นค่าจริงของอาร์เรย์) รหัสต่อไปนี้จะทำ:

สำหรับความพึงพอใจของเงื่อนไข (ทั้งหมด) หลายประการ:

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

สำหรับความพึงพอใจของเงื่อนไข (หรือ) หลายประการ:

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

2
โปรดทราบว่า numpy.where จะไม่ส่งคืนอาร์เรย์ของดัชนีเท่านั้น แต่จะส่งคืน tuple (ผลลัพธ์ของ condition.nonzero ()) ที่มีอาร์เรย์ - ในกรณีนี้(the array of indices you want,)คุณจะต้องselect_indices = np.where(...)[0]ได้ผลลัพธ์ที่ต้องการ และคาดหวัง
calavicci

5

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

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

ข้อดีคือคุณสามารถเพิ่มข้อ จำกัด อีกมากมายในฟังก์ชันเวกเตอร์

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


1
นี่ไม่ใช่วิธีที่ดีในการทำดัชนีใน NumPy (มันจะช้ามาก)
Alex Riley

1

จริงๆแล้วฉันจะทำแบบนี้:

L1 คือรายการดัชนีองค์ประกอบที่ตรงตามเงื่อนไข 1; (บางทีคุณสามารถใช้somelist.index(condition1)หรือnp.where(condition1)รับ L1)

ในทำนองเดียวกันคุณจะได้รับ L2 รายการองค์ประกอบที่ตรงตามเงื่อนไข 2;

จากนั้นคุณจะพบสี่แยกที่ใช้ intersect(L1,L2)แล้วคุณจะพบสี่แยกโดยใช้

นอกจากนี้คุณยังสามารถค้นหาจุดตัดของหลายรายการได้หากคุณได้รับเงื่อนไขที่หลากหลาย

จากนั้นคุณสามารถใช้ดัชนีในอาเรย์อื่นเช่น x


0

สำหรับอาร์เรย์ 2 มิติคุณสามารถทำได้ สร้างหน้ากาก 2D โดยใช้เงื่อนไข พิมพ์หน้ากากสภาพให้เป็น int หรือลอยขึ้นอยู่กับอาร์เรย์และคูณมันด้วยอาร์เรย์เดิม

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.]])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.