Numpy, birden çok koşulun çalıştığı yerde


132

Uzaklık adı verilen bir dizi mesafem var. İki değer arasındaki mesafeleri seçmek istiyorum. Bunu yapmak için aşağıdaki kod satırını yazdım:

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

Ancak bu, yalnızca koşul için seçer

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

Komutları geçici bir değişken kullanarak sırayla yaparsam iyi çalışıyor. Yukarıdaki kod neden çalışmıyor ve onu nasıl çalıştırabilirim?

Şerefe

Yanıtlar:


203

Sizin durumunuzda en iyi yol , iki kriterinizi bir kriter olarak değiştirmektir:

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

Sadece bir boolean dizi oluşturur ve bence, diyor çünkü okumak daha kolaydır olan distbir mesafede drya r? ( rBaşlangıçtan ziyade ilgi alanınızın merkezi olarak yeniden tanımlasam da r = r + dr/2.) Ancak bu, sorunuzun yanıtını vermiyor.


Sorunuzun cevabı: Sadece kriterlerinize uymayan unsurları filtrelemeye çalışıyorsanız,
aslında ihtiyacınız yok:wheredists

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

Çünkü &size bir elementwise verecektir and(parantezler gereklidir).

Veya whereherhangi bir nedenle kullanmak istiyorsanız , şunları yapabilirsiniz:

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

Nedeni:
Çalışmamasının nedeni np.where, bir boole dizisi değil, bir dizin listesi döndürmesidir. andElbette beklediğiniz True/ Falsedeğerlerine sahip olmayan iki sayı listesi arasına girmeye çalışıyorsunuz . Eğer ave bikisi de Truedeğerler, daha sonra a and bdöner b. Yani böyle bir şey söylemek [0,1,2] and [2,3,4]size verecektir [2,3,4]. İşte eylemde:

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

Karşılaştırmayı beklediğiniz şey basitçe boole dizisiydi, örneğin

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)

Şimdi np.wherebirleşik boole dizisini çağırabilirsiniz :

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

Veya basit bir şekilde orijinal diziyi süslü indekslemeyi kullanarak boole dizisiyle indeksleyin

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

61

Kabul edilen cevap sorunu yeterince iyi açıkladı. Bununla birlikte, birden çok koşulu uygulamak için daha Numpythonic yaklaşım, numpy mantıksal işlevleri kullanmaktır . Bu ase'de şunları kullanabilirsiniz np.logical_and:

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

11

Burada işaret edilecek ilginç bir şey; OR ve AND'yi kullanmanın olağan yolu bu durumda işe yarayacaktır, ancak küçük bir değişiklikle. "Ve" yerine ve "veya" yerine Ampersand (&) ve Boru Operatörü (|) kullanın ve çalışacaktır.

Kullandığımız zaman 've' :

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

Kullandığımız zaman işareti (&) :

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

Pandas Dataframe durumunda birden fazla filtre uygulamaya çalıştığımızda da bu aynıdır. Şimdi bunun arkasındaki mantık, Mantıksal Operatörler ve Bitsel Operatörler ile bir şeyler yapmak zorundadır ve aynı şeyi daha iyi anlamak için, bu yanıtı veya stackoverflow'daki benzer Q / A'yı incelemeyi öneririm .

GÜNCELLEME

Bir kullanıcı, parantez içinde neden (ar> 3) ve (ar <6) vermeye ihtiyaç olduğunu sordu. İşte şey şu. Burada neler olduğu hakkında konuşmaya başlamadan önce, Python'daki Operatör önceliğinin bilinmesi gerekiyor.

BODMAS'ın ne hakkında olduğuna benzer şekilde, python da önce yapılması gerekenlere öncelik verir. Parantez içindeki maddeler önce gerçekleştirilir ve ardından bitsel operatör işe gelir. Her iki durumda da "(", ")" kullanıp kullanmadığınızda neler olduğunu aşağıda göstereceğim.

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

Hiçbir parantez burada olduğundan, bitsel operatörü ( &) sen bile ne soruyorsun mantıksal almak için o burada karıştı oluyor VE operatör öncelik tabloda gördüğünüz çünkü eğer, bir, &daha önceliklidir verilir <veya >operatörler. En düşük öncelikten en yüksek önceliğe doğru tablo.

görüntü açıklamasını buraya girin

Hatta <ve >işlemini gerçekleştirmiyor ve mantıksal bir AND işlemi yapması istenmiyor. Bu yüzden bu hatayı veriyor.

Aşağıdakiler hakkında daha fazla bilgi edinmek için aşağıdaki bağlantıya bakılabilir: operatör önceliği

Şimdi Durum 2'ye:

Desteği kullanırsanız, ne olacağını açıkça görürsünüz.

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)

Doğru ve Yanlış olmak üzere iki dizi. Ve bunlar üzerinde kolayca mantıksal VE işlemi gerçekleştirebilirsiniz. Hangi size verir:

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

Ve dinlenin, np. Nerede, nerede olursa olsun, nerede True ilk değeri atarsa ​​(yani burada 'yo') ve False ise diğerini (yani burada, orijinali korurken).

Bu kadar. Umarım sorguyu iyi açıkladım.


1
Neden ()etrafta dolaşmak zorundasın (ar>3)ve (ar>6)?
RTrain3k

Bu gerçekten güzel bir soru. O kadar güzel bir soru ki, kendi kendime düşünmek zorunda kaldım, yeryüzünde buna ihtiyacım var. Ben de yaptım, bir meslektaşıma sordum ve tartıştık ve şimdi sizin için bir çözümüm var. Yanıta UPDATE olarak koymak. Gerçekten çok basit ama gerçekten anlaşılması zor bir şey.
Amit Amola

RTrain3k güncellemesini kontrol edin, sorgunuzu cevapladım.
Amit Amola

5

Bu np.vectorizetür görevler için kullanmayı seviyorum . Aşağıdakileri göz önünde bulundur:

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

Net çıktı np.argwhereyerine de kullanabilirsiniz np.where. Ama bu senin çağrın :)

Umarım yardımcı olur.


2

Deneyin:

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

2

Bu çalışmalı:

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

En zarif yol ~~


2

Deneyin:

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

Çıktı: (dizi ([2, 3]),)

Daha fazla ayrıntı için Mantık işlevlerine bakabilirsiniz.


0

Bu basit örnek üzerinde çalıştım

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
Bu durumda yinelemeye gerek yoktur. NumPy'de boole endekslemesi vardır.
M456
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.