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?

Bob
sumber

Jawaban:

220

Ekspresi Anda berfungsi jika Anda menambahkan tanda kurung:

>>> y[(1 < x) & (x < 5)]
array(['o', 'o', 'a'], 
      dtype='|S1')
jfs
sumber
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.

Mark Mikofski
sumber
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
Niat Baik
sumber
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.


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

Shuo Yang
sumber
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.]])
Gautam Sreekumar
sumber