Bagaimana cara memilih elemen dari kondisi yang diberikan array?


156

Misalkan saya punya array numpy x = [5, 2, 3, 1, 4, 5], y = ['f', 'o', 'o', 'b', 'a', 'r']. Saya ingin memilih elemen yang ysesuai dengan elemen dalamx yang lebih besar dari 1 dan kurang dari 5.

Saya mencoba

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

tetapi ini tidak berhasil. Bagaimana saya melakukan ini?

Jawaban:


220

Ekspresi Anda berfungsi jika Anda menambahkan tanda kurung:

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

1
Itu bagus .. vecMask = 1 <x menghasilkan topeng vektor seperti vecMask = (False, True, ...), yang dapat dikombinasikan dengan topeng vektor lainnya. Setiap elemen adalah kondisi untuk mengambil elemen-elemen dari vektor sumber (Benar) atau tidak (Salah). Ini dapat digunakan juga dengan versi lengkap numpy.extract (vecMask, vecSrc), atau numpy.where (vecMask, vecSrc, vecSrc2).
MasterControlProgram

6
@ JennyYueJin: Itu terjadi karena diutamakan. (Bitwise) &memiliki prioritas lebih tinggi dari <dan >, yang pada gilirannya memiliki prioritas lebih tinggi daripada (logis) and. x > 1 and x < 5mengevaluasikan ketidaksetaraan pertama dan kemudian konjungsi logis; x > 1 & x < 5mengevaluasi konjungsi bitwise dari 1dan (nilai-nilai dalam) x, maka ketidaksetaraan. (x > 1) & (x < 5)memaksa ketidaksetaraan untuk mengevaluasi terlebih dahulu, sehingga semua operasi terjadi dalam urutan yang dimaksudkan dan hasilnya semua didefinisikan dengan baik. Lihat dokumen di sini.
calavicci

@ ru111 Ia bekerja pada Python 3.6 juga (tidak ada alasan untuk berhenti bekerja).
jfs

Saya mendapatkan "ValueError: Nilai kebenaran dari array dengan lebih dari satu elemen adalah ambigu. Gunakan a.any () atau a.all ()"
ru111

@ ru111 Anda harus menulis (0 < x) & (x < 10)(seperti yang ditunjukkan dalam jawaban) alih-alih 0 < x < 10yang tidak bekerja untuk array numpy pada versi Python.
jfs

34

IMO OP tidak benar-benar ingin np.bitwise_and()(alias &) tetapi sebenarnya ingin np.logical_and()karena mereka membandingkan nilai-nilai logis seperti Truedan False- lihat posting SO ini pada logis vs bitwise untuk melihat perbedaannya.

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

Dan cara yang setara untuk melakukan ini adalah dengan np.all()mengatur axisargumen dengan tepat.

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

dengan angka:

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

jadi menggunakan np.all()lebih lambat, tetapi &dan logical_andhampir sama.


7
Anda perlu sedikit berhati-hati tentang bagaimana Anda berbicara tentang apa yang dievaluasi. Misalnya, dalam output = y[np.logical_and(x > 1, x < 5)], x < 5 adalah dievaluasi (mungkin menciptakan sebuah array yang sangat besar), meskipun itu argumen kedua, karena evaluasi yang terjadi di luar fungsi. TKI, logical_andmelewati dua argumen yang sudah dievaluasi. Ini berbeda dari kasus biasa a and b, di mana btidak dievaluasi apakah abenar trike.
DSM

15
tidak ada perbedaan antara bitwise_and () dan logical_and () untuk array boolean
jfs

21

Tambahkan satu detail ke jawaban @JF Sebastian dan @Mark Mikofski:
Jika seseorang ingin mendapatkan indeks yang sesuai (bukan nilai aktual array), kode berikut akan melakukannya:

Untuk memuaskan beberapa (semua) kondisi:

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

Untuk memenuhi beberapa (atau) kondisi:

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

2
Perhatikan bahwa numpy.where tidak hanya mengembalikan array indeks, tetapi sebaliknya akan mengembalikan tuple (output dari condition.nonzero ()) yang berisi array - dalam hal ini (the array of indices you want,),, jadi Anda harus select_indices = np.where(...)[0]mendapatkan hasil yang Anda inginkan dan berharap.
calavicci

5

Saya suka menggunakan np.vectorizeuntuk tugas-tugas seperti itu. Pertimbangkan yang berikut ini:

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

Keuntungannya adalah Anda dapat menambahkan lebih banyak jenis kendala dalam fungsi vektor.

Semoga ini bisa membantu.


1
Ini bukan cara yang baik untuk melakukan pengindeksan di NumPy (ini akan sangat lambat).
Alex Riley

1

Sebenarnya saya akan melakukannya dengan cara ini:

L1 adalah daftar indeks elemen yang memenuhi kondisi 1; (mungkin Anda dapat menggunakan somelist.index(condition1)atau np.where(condition1)untuk mendapatkan L1.)

Demikian pula, Anda mendapatkan L2, daftar elemen yang memenuhi syarat 2;

Kemudian Anda menemukan persimpangan menggunakan intersect(L1,L2).

Anda juga dapat menemukan persimpangan beberapa daftar jika Anda memenuhi beberapa persyaratan.

Kemudian Anda bisa menerapkan indeks di larik lain, misalnya, x.


0

Untuk array 2D, Anda bisa melakukan ini. Buat topeng 2D menggunakan kondisinya. Ketikkan masker kondisi ke int atau float, tergantung pada array, dan kalikan dengan array asli.

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.]])
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.