Numpy di mana berfungsi berbagai kondisi

132

Saya memiliki array jarak yang disebut dists. Saya ingin memilih dist yang berada di antara dua nilai. Saya menulis baris kode berikut untuk melakukan itu:

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

Namun ini hanya memilih untuk kondisi

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

Jika saya melakukan perintah secara berurutan dengan menggunakan variabel sementara itu berfungsi dengan baik. Mengapa kode di atas tidak berfungsi, dan bagaimana cara membuatnya berfungsi?

Bersulang

pengguna1654183
sumber

Jawaban:

203

Cara terbaik dalam kasus khusus Anda adalah mengubah dua kriteria Anda menjadi satu kriteria:

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

Ini hanya menciptakan satu array boolean, dan menurut saya lebih mudah dibaca karena dikatakan, apakah distdalam dratau r? (Meskipun saya akan mendefinisikan ulang rmenjadi pusat wilayah minat Anda alih-alih awal, jadi r = r + dr/2.) Tapi itu tidak menjawab pertanyaan Anda.


Jawaban atas pertanyaan
Anda : Anda sebenarnya tidak perlu wherejika Anda hanya mencoba menyaring elemen-elemen distsyang tidak sesuai dengan kriteria Anda:

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

Karena itu &akan memberi Anda elemenwise and(tanda kurung diperlukan).

Atau, jika Anda ingin menggunakan wherekarena suatu alasan, Anda dapat melakukan:

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

Mengapa:
Alasan tidak berhasil adalah karena np.wheremengembalikan daftar indeks, bukan array boolean. Anda mencoba untuk mendapatkan di andantara dua daftar angka, yang tentu saja tidak memiliki True/ Falsenilai yang Anda harapkan. Jika adan bkeduanya adalah Truenilai, maka a and bkembali b. Jadi mengatakan sesuatu seperti [0,1,2] and [2,3,4]hanya akan memberi Anda [2,3,4]. Ini dia sedang beraksi:

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

Apa yang Anda harapkan untuk dibandingkan hanyalah array boolean, misalnya

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)

Sekarang Anda dapat memanggil np.wherearray boolean gabungan:

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

Atau cukup indeks array asli dengan array boolean menggunakan pengindeksan mewah

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

Jawaban yang diterima menjelaskan masalahnya dengan cukup baik. Namun, pendekatan yang lebih Numpythonic untuk menerapkan beberapa kondisi adalah dengan menggunakan fungsi numpy logical . Dalam ase ini Anda dapat menggunakan np.logical_and:

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

Satu hal yang menarik untuk ditunjukkan di sini; cara biasa menggunakan ATAU dan DAN juga akan bekerja dalam kasus ini, tetapi dengan perubahan kecil. Alih-alih "dan" dan bukannya "atau", alih-alih gunakan Ampersand (&) dan Operator Pipa (|) dan itu akan bekerja.

Saat kami menggunakan 'dan' :

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

Saat kami menggunakan Ampersand (&) :

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

Dan ini sama dalam kasus ketika kami mencoba menerapkan beberapa filter dalam kasus panda Dataframe. Sekarang alasan di balik ini harus melakukan sesuatu dengan Logical Operators dan Bitwise Operators dan untuk lebih banyak pemahaman tentang hal yang sama, saya sarankan untuk memeriksa jawaban ini atau T / A serupa di stackoverflow.

MEMPERBARUI

Seorang pengguna bertanya, mengapa ada kebutuhan untuk memberi (ar> 3) dan (ar <6) di dalam tanda kurung. Nah, ini masalahnya. Sebelum saya mulai berbicara tentang apa yang terjadi di sini, kita perlu tahu tentang Operator diutamakan dalam Python.

Mirip dengan apa BODMAS tentang, python juga memberikan prioritas pada apa yang harus dilakukan terlebih dahulu. Item di dalam kurung dilakukan terlebih dahulu dan kemudian operator bitwise mulai bekerja. Saya akan menunjukkan di bawah apa yang terjadi dalam kedua kasus ketika Anda menggunakan dan tidak menggunakan "(", ")".

Kasus 1:

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)

Karena tidak ada tanda kurung di sini, operator bitwise ( &) semakin bingung di sini bahwa apa yang Anda minta menjadi logis DAN, karena dalam tabel prioritas operator jika Anda lihat, &diberikan prioritas <atau >operator. Ini tabel dari mulai dari yang lebih rendah hingga yang paling tinggi.

masukkan deskripsi gambar di sini

Bahkan tidak melakukan <dan >operasi dan diminta untuk melakukan operasi DAN logis. Jadi itu sebabnya itu memberikan kesalahan itu.

Satu dapat memeriksa tautan berikut untuk mempelajari lebih lanjut tentang: prioritas operator

Sekarang ke Kasus 2:

Jika Anda menggunakan braket, Anda melihat dengan jelas apa yang terjadi.

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)

Dua array Benar dan Salah. Dan Anda dapat dengan mudah melakukan operasi DAN logis pada mereka. Yang memberi Anda:

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

Dan sisanya Anda tahu, np.where, untuk kasus yang diberikan, di mana pun Benar, memberikan nilai pertama (yaitu di sini 'yo') dan jika Salah, yang lain (yaitu di sini, menyimpan yang asli).

Itu saja. Saya harap saya menjelaskan kueri dengan baik.

Amit Amola
sumber
1
Mengapa Anda harus ()berkeliling (ar>3)dan (ar>6)?
RTrain3k
Itu pertanyaan yang sangat bagus. Pertanyaan yang sangat bagus sehingga saya harus berpikir sendiri bahwa apa yang sebenarnya dibutuhkan di sana. Jadi saya melakukannya, bertanya pada seorang kolega juga dan kami berdiskusi dan sekarang saya punya solusi untuk Anda. Masukkan itu dalam jawaban sebagai PEMBARUAN. Ini sangat sederhana namun hal yang sulit untuk dipahami.
Amit Amola
Lihat pembaruan RTrain3k, saya telah menjawab pertanyaan Anda.
Amit Amola
5

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

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

Anda juga dapat menggunakan np.argwheresebagai gantinya np.whereuntuk menghapus output. Tapi itu panggilan Anda :)

Semoga ini bisa membantu.


sumber
2

Mencoba:

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

Ini seharusnya bekerja:

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

Cara paling elegan ~~

Qhan
sumber
2

Mencoba:

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

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

Anda dapat melihat fungsi Logika untuk lebih jelasnya.

Xiong-Hui Chen
sumber
0

Saya telah mengerjakan contoh sederhana ini

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]
Kiriloff
sumber
6
Tidak perlu mengulangi dalam kasus ini. NumPy memiliki pengindeksan boolean.
M456