Pandalar'da mantıksal indeksleme için mantıksal operatörler


154

Pandalar'da boole endeksi ile çalışıyorum. Soru, ifadenin neden:

a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]

oysa iyi çalışıyor

a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]

hatalı çıkar?

Misal:

a=pd.DataFrame({'x':[1,1],'y':[10,20]})

In: a[(a['x']==1)&(a['y']==10)]
Out:    x   y
     0  1  10

In: a[(a['x']==1) and (a['y']==10)]
Out: ValueError: The truth value of an array with more than one element is ambiguous.     Use a.any() or a.all()

6
Bunun nedeni, numpy dizileri ve panda serilerinin, dizideki / serideki her öğeyi bir başkasıyla karşılaştırdığınızda mantıksal değil bitsel işleçleri kullanmasıdır. Bu nedenle, bu durumda mantıksal operatörün kullanılması mantıklı değildir. ilgili
olanlara

9
Python'da and != &. andPython operatör ise, geçersiz kılınan olamaz &operatör ( __and__) kutu. Bu nedenle seçim &numpy ve pandalarda kullanım.
Steven Rumbalski

Yanıtlar:


209

Dediğinde

(a['x']==1) and (a['y']==10)

Örtük olarak Python'dan değerleri dönüştürmesini (a['x']==1)ve (a['y']==10)boole değerlerini almasını istiyorsunuz .

NumPy dizileri (1'den büyük uzunluk) ve Series gibi Pandas nesnelerinin boolean değeri yoktur - başka bir deyişle,

ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().

boole değeri olarak kullanıldığında. Çünkü ne zaman Doğru veya Yanlış olması belirsizdir . Bazı kullanıcılar, Python listesi gibi sıfır olmayan bir uzunluğa sahip olduklarında Doğru olduklarını varsayabilir. Diğerleri ancak tüm unsurları Doğru olduğunda bunun Gerçek olmasını isteyebilir . Diğerleri , öğelerinden herhangi biri Doğru ise , Doğru olmasını isteyebilir .

Çok fazla çelişkili beklentiler olduğu için, NumPy ve Pandas tasarımcıları tahmin etmeyi reddediyor ve bunun yerine bir ValueError oluşturuyor.

Bunun yerine, hangi davranışı istediğinizi belirtmek için empty(), all()veya any()yöntemini çağırarak açık olmalısınız .

Ancak bu durumda, boole değerlendirmesi istemediğiniz, element- mantıksal mantıksal ve istediğiniz gibi görünüyor . &İkili operatörün yaptığı şey budur :

(a['x']==1) & (a['y']==10)

bir boole dizisi döndürür.


Bu arada, alexpmil'in belirttiği gibi, parantezler zorunludur, çünkü &daha yüksek bir operatör önceliğine sahiptir ==. Parantez olmadan zincirleme karşılaştırmaya eşdeğer a['x']==1 & a['y']==10olarak değerlendirilir . Bu formun bir ifadesidir . İki Seri ile birlikte kullanılması yukarıdaki ile aynıdır . Bu nedenle parantezler zorunludur.a['x'] == (1 & a['y']) == 10(a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10)Series and SeriesandValueError


3
numpy dizileri , uzunluk bir ise bu özelliğe sahiptir . Sadece panda devs (inatla) tahmin etmeyi reddediyor: p
Andy Hayden

4
'&', 'Ve' ile aynı belirsiz eğriyi taşımıyor mu? '&' Söz konusu olduğunda nasıl olurlar, birdenbire tüm kullanıcılar bunun element-bilge olması gerektiğini kabul ederken, 've' gördüklerinde beklentileri değişir mi?
Indominus

16
@Indominus: Python dilinin kendisi , ifadenin ve öğesinin x and ydeğerlendirilmesini tetiklemesini gerektirir . Python "önce değerlendirir ; yanlışsa değeri döndürülür; aksi takdirde değerlendirilir ve elde edilen değer döndürülür." Yani sözdizimi eleman-bilge mantıksal olarak kullanılamaz- ve sadece veya geri döndürülebilir. Buna karşılık, istediğimiz her şeyi döndürmek için tetikleyiciler ve yöntem tanımlanabilir. bool(x)bool(y)xxyx and yxyx & yx.__and__(y)__and__
unutbu

2
Dikkat edilmesi gereken nokta: ==Maddenin etrafındaki parantezler zorunludur . a['x']==1 & a['y']==10sorudakiyle aynı hatayı döndürür.
Alex P. Miller

1
"|" Ne içindir?
Euler_Salter

62

TLDR; Pandalar içinde Mantıksal Operatörler vardır &, |ve ~, ve parantez (...)önemli!

Python var and, orve notmantıksal operatörler skalerler ile çalışmak üzere tasarlanmıştır. Bu yüzden Pandalar bu işlevin vektörize (element-wise) versiyonunu elde etmek için daha iyisini yapmak ve bitsel operatörleri geçersiz kılmak zorunda kaldı .

Python'da aşağıdakiler ( exp1ve exp2bir boole sonucunu değerlendiren ifadelerdir) ...

exp1 and exp2              # Logical AND
exp1 or exp2               # Logical OR
not exp1                   # Logical NOT

... tercüme edilecek ...

exp1 & exp2                # Element-wise logical AND
exp1 | exp2                # Element-wise logical OR
~exp1                      # Element-wise logical NOT

pandalar için.

Mantıksal işlem gerçekleştirme sürecinde bir ValueErroralırsanız, gruplama için parantez kullanmanız gerekir:

(exp1) op (exp2)

Örneğin,

(df['col1'] == x) & (df['col2'] == y) 

Ve bunun gibi.


Boolean Dizinleme : Ortak bir işlem, verileri filtrelemek için mantıksal koşullar aracılığıyla boolean maskeleri hesaplamaktır. Pandalar üç operatör sağlar:&mantıksal VE,|mantıksal VEYA ve~mantıksal DEĞİL için.

Aşağıdaki kurulumu düşünün:

np.random.seed(0)
df = pd.DataFrame(np.random.choice(10, (5, 3)), columns=list('ABC'))
df

   A  B  C
0  5  0  3
1  3  7  9
2  3  5  2
3  4  7  6
4  8  8  1

Mantıksal VE

İçin dfyukarıda, A <5 ve B> 5. Bu ayrı ayrı her durum için maskeler bilgisayar ve bunları operatörü kullanılarak eklenmesiyle yapılır tüm satırları iade etmek istiyorum söylüyorlar.

Aşırı Yüklü Bitsel &Operatör
Devam etmeden önce lütfen aşağıdaki dokümanların bu özel alıntısına dikkat edin:

Diğer bir yaygın işlem, verileri filtrelemek için boole vektörlerinin kullanılmasıdır. İşleçler: |için or, &için andve ~içindir not. Bu parantez kullanarak gruplandırılması gerekir gibi bir ifade değerlendirecek varsayılan Python tarafından yana df.A > 2 & df.B < 3olarak df.A > (2 & df.B) < 3istenen değerlendirme sırası iken, (df.A > 2) & (df.B < 3).

Yani, bu düşünceyle, bilge mantıksal VE bitsel operatör ile uygulanabilir &:

df['A'] < 5

0    False
1     True
2     True
3     True
4    False
Name: A, dtype: bool

df['B'] > 5

0    False
1     True
2    False
3     True
4     True
Name: B, dtype: bool

(df['A'] < 5) & (df['B'] > 5)

0    False
1     True
2    False
3     True
4    False
dtype: bool

Ve sonraki filtreleme adımı basitçe,

df[(df['A'] < 5) & (df['B'] > 5)]

   A  B  C
1  3  7  9
3  4  7  6

Parantez koşullu operatörler üzerinde yüksek önceliğe sahip bit operatörleri, varsayılan öncelik sırasını geçersiz kılmak için kullanılır <ve >. Python belgelerinde Operatör Önceliği bölümüne bakın .

Parantez kullanmazsanız, ifade yanlış değerlendirilir. Örneğin, yanlışlıkla

df['A'] < 5 & df['B'] > 5

Şu şekilde ayrıştırılır

df['A'] < (5 & df['B']) > 5

Hangi olur,

df['A'] < something_you_dont_want > 5

Bu da olur ( zincirleme operatör karşılaştırmasında python belgelerine bakın ),

(df['A'] < something_you_dont_want) and (something_you_dont_want > 5)

Hangi olur,

# Both operands are Series...
something_else_you_dont_want1 and something_else_you_dont_want2

Hangi atar

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Yani, bu hatayı yapma! 1

Parantez Gruplarından Kaçınmak
Düzeltme aslında oldukça basittir. Çoğu işleç DataFrames için karşılık gelen bir bağlı yönteme sahiptir. Tek tek maskeler koşullu işleçler yerine işlevler kullanılarak oluşturulmuşsa, değerlendirme sırasını belirtmek için artık ebeveynlere göre gruplandırmanıza gerek kalmayacaktır:

df['A'].lt(5)

0     True
1     True
2     True
3     True
4    False
Name: A, dtype: bool

df['B'].gt(5)

0    False
1     True
2    False
3     True
4     True
Name: B, dtype: bool

df['A'].lt(5) & df['B'].gt(5)

0    False
1     True
2    False
3     True
4    False
dtype: bool

Esnek Karşılaştırmalar bölümüne bakın . . Özetlemek gerekirse,

╒════╤════════════╤════════════╕
     Operator    Function   
╞════╪════════════╪════════════╡
  0  >           gt         
├────┼────────────┼────────────┤
  1  >=          ge         
├────┼────────────┼────────────┤
  2  <           lt         
├────┼────────────┼────────────┤
  3  <=          le         
├────┼────────────┼────────────┤
  4  ==          eq         
├────┼────────────┼────────────┤
  5  !=          ne         
╘════╧════════════╧════════════╛

Parantezlerden kaçınmak için başka bir seçenek de DataFrame.query(veya eval) kullanmaktır :

df.query('A < 5 and B > 5')

   A  B  C
1  3  7  9
3  4  7  6

Ben var yoğun belgelenmiş queryve evaliçinde pd.eval kullanarak pandalar Dinamik ifade değerlendirme () .

operator.and_
Bu işlemi işlevsel bir şekilde gerçekleştirmenizi sağlar. Dahili Series.__and__olarak, bitsel operatöre karşılık gelen çağrılar .

import operator 

operator.and_(df['A'] < 5, df['B'] > 5)
# Same as,
# (df['A'] < 5).__and__(df['B'] > 5) 

0    False
1     True
2    False
3     True
4    False
dtype: bool

df[operator.and_(df['A'] < 5, df['B'] > 5)]

   A  B  C
1  3  7  9
3  4  7  6

Genellikle buna ihtiyacınız olmaz, ancak bilmek faydalıdır.

Genelleme: np.logical_and(ve logical_and.reduce) Parantez gruplandırmasına ihtiyaç duymayan
başka bir alternatif kullanmak np.logical_and:

np.logical_and(df['A'] < 5, df['B'] > 5)

0    False
1     True
2    False
3     True
4    False
Name: A, dtype: bool

df[np.logical_and(df['A'] < 5, df['B'] > 5)]

   A  B  C
1  3  7  9
3  4  7  6

np.logical_andbir ufunc (Evrensel İşlevler) ve çoğu ufunc'un bir reduceyöntemi vardır. Bu logical_and, AND için birden fazla masanız varsa genellemenin daha kolay olduğu anlamına gelir . Örneğin, AND maskelerine m1ve m2ile m3birlikte &,

m1 & m2 & m3

Ancak, daha kolay bir seçenek

np.logical_and.reduce([m1, m2, m3])

Bu güçlüdür, çünkü daha karmaşık bir mantıkla bunun üzerine inşa etmenizi sağlar (örneğin, bir liste kavrayışında dinamik olarak maskeler oluşturmak ve hepsini eklemek):

import operator

cols = ['A', 'B']
ops = [np.less, np.greater]
values = [5, 5]

m = np.logical_and.reduce([op(df[c], v) for op, c, v in zip(ops, cols, values)])
m 
# array([False,  True, False,  True, False])

df[m]
   A  B  C
1  3  7  9
3  4  7  6

1 - Biliyorum bu noktaya uyuyorum, ama lütfen bana katlan. Bu çok , çok yaygın bir başlangıç ​​hatasıdır ve çok ayrıntılı bir şekilde açıklanmalıdır.


Mantıksal VEYA

İçin dfyukarıda, tüm satırları A == 3 veya B == 7 iade etmek istiyorum söylüyorlar.

Aşırı yüklenmiş Bitsel |

df['A'] == 3

0    False
1     True
2     True
3    False
4    False
Name: A, dtype: bool

df['B'] == 7

0    False
1     True
2    False
3     True
4    False
Name: B, dtype: bool

(df['A'] == 3) | (df['B'] == 7)

0    False
1     True
2     True
3     True
4    False
dtype: bool

df[(df['A'] == 3) | (df['B'] == 7)]

   A  B  C
1  3  7  9
2  3  5  2
3  4  7  6

Henüz yapmadıysanız, lütfen yukarıdaki Mantıksal VE bölümünü de okuyun , tüm uyarılar burada geçerlidir.

Alternatif olarak, bu işlem aşağıdakilerle belirtilebilir

df[df['A'].eq(3) | df['B'].eq(7)]

   A  B  C
1  3  7  9
2  3  5  2
3  4  7  6

operator.or_
Series.__or__Kaputun altında aramalar .

operator.or_(df['A'] == 3, df['B'] == 7)
# Same as,
# (df['A'] == 3).__or__(df['B'] == 7)

0    False
1     True
2     True
3     True
4    False
dtype: bool

df[operator.or_(df['A'] == 3, df['B'] == 7)]

   A  B  C
1  3  7  9
2  3  5  2
3  4  7  6

np.logical_or
İki koşul için logical_orşunları kullanın :

np.logical_or(df['A'] == 3, df['B'] == 7)

0    False
1     True
2     True
3     True
4    False
Name: A, dtype: bool

df[np.logical_or(df['A'] == 3, df['B'] == 7)]

   A  B  C
1  3  7  9
2  3  5  2
3  4  7  6

Birden çok maske için logical_or.reduceşunları kullanın :

np.logical_or.reduce([df['A'] == 3, df['B'] == 7])
# array([False,  True,  True,  True, False])

df[np.logical_or.reduce([df['A'] == 3, df['B'] == 7])]

   A  B  C
1  3  7  9
2  3  5  2
3  4  7  6

Mantıksal DEĞİL

Bir maske verildi, örneğin

mask = pd.Series([True, True, False])

Her bir boolean değerini tersine çevirmeniz gerekiyorsa (sonuçta bu şekilde olur [False, False, True]), aşağıdaki yöntemlerden herhangi birini kullanabilirsiniz.

Bitsel ~

~mask

0    False
1    False
2     True
dtype: bool

Yine, ifadelerin parantez içine alınması gerekir.

~(df['A'] == 3)

0     True
1    False
2    False
3     True
4     True
Name: A, dtype: bool

Bu dahili olarak

mask.__invert__()

0    False
1    False
2     True
dtype: bool

Ama doğrudan kullanmayın.

operator.inv
Dahili __invert__olarak Seriyi arar .

operator.inv(mask)

0    False
1    False
2     True
dtype: bool

np.logical_not
Bu numpy çeşididir.

np.logical_not(mask)

0    False
1    False
2     True
dtype: bool

Not, np.logical_andyerine np.bitwise_and, logical_orile bitwise_orve logical_notile ikame edilebilir invert.


TLDR'deki @ cs95, element-bilge boole OR |için numpy.bitwise_or, bunun yerine eşdeğer olanı kullanmayı savunuyorsunuz numpy.logical_or. Neden olduğunu sorabilir miyim? numpy.logical_orBu görev için özel olarak tasarlanmamış mı ? Neden her bir eleman çifti için bitsel yapmanın yükünü ekliyoruz?
flow2k

@ flow2k lütfen ilgili metni teklif edebilir misiniz? Ne demek istediğinizi bulamıyorum. FWIW Mantıksal_ * 'ın işleçlerin doğru işlevsel eşdeğeri olduğunu iddia ediyorum.
cs95

@ cs95 Cevabın ilk satırına atıfta bulunuyorum: "TLDR; Pandalar'daki Mantıksal Operatörler &, | ve ~".
flow2k

@ flow2k Kelimenin tam anlamıyla dokümantasyonda : "Başka bir yaygın işlem, verileri filtrelemek için boole vektörlerinin kullanılmasıdır. Operatörler: | for veya, & for ve, ve ~ için değil."
cs95

@ cs95, tamam, sadece bu bölümü okudum ve |element-bilge boole işlemi için kullanıyor. Ama bana göre, bu belge daha bir "öğretici" ve aksine, ben bu API referansları gerçeğin kaynağına daha yakın hissediyorum: numpy.bitwise_or ve numpy.logical_or - bu yüzden ne olduğunu anlamaya çalışıyorum burada açıklanmıştır.
flow2k

4

Pandalar'da mantıksal indeksleme için mantıksal operatörler

Bu Python herhangi kullanamazsınız fark etmek önemlidir mantıksal operatörler ( and, orya notüzerine) pandas.Seriesveya pandas.DataFrames (benzer sen bunları kullanamaz numpy.arraybirden fazla eleman ile s). Bunları kullanamamanızın nedeni, örtük olarak boolişlenenlerini bir İstisna fırlatan çağrılarıdır , çünkü bu veri yapıları bir dizinin booleanının belirsiz olduğuna karar vermiştir:

>>> import numpy as np
>>> import pandas as pd
>>> arr = np.array([1,2,3])
>>> s = pd.Series([1,2,3])
>>> df = pd.DataFrame([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> bool(df)
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Bunu daha kapsamlı kapağıyla çıktı cevabım "Bir Serisinin Hakikat değeri belirsiz. Kullanım a.empty, a.bool (), a.item (), a.any () veya a.All ()" Q + A .

NumPys mantıksal işlevleri

Ancak NumPy kullanılabilir fonksiyonları gibi bu operatörlere öğeye çalışma eşdeğerleri içerir numpy.array, pandas.Series, pandas.DataFrameya da başka bir (uygun olarak) numpy.arrayalt sınıfından:

Yani, esasen, bir kişi kullanmalıdır ( varsayalım df1ve df2pandalar DataFrames):

np.logical_and(df1, df2)
np.logical_or(df1, df2)
np.logical_not(df1)
np.logical_xor(df1, df2)

Boolelar için bitsel fonksiyonlar ve bitsel operatörler

Bununla birlikte, boolean NumPy dizisi, panda Serisi veya panda DataFrames'ınız varsa, element-bilge bitwise işlevlerini de kullanabilirsiniz (mantıksal işlevlerden ayırt edilemeyen - veya en azından olmalıdır - booleans için):

Tipik olarak operatörler kullanılır. Ancak karşılaştırma operatörleri ile birleştirildiğinde karşılaştırmayı parantez içine almayı unutmamak gerekir, çünkü bitsel operatörler karşılaştırma operatörlerinden daha yüksek önceliğe sahiptir :

(df1 < 10) | (df2 > 10)  # instead of the wrong df1 < 10 | df2 > 10

Normalde yazma böylece Python mantıksal operatörler karşılaştırma operatörleri daha düşük precendence sahip olduğundan bu rahatsız edici olabilir a < 10 and b > 10( ave börneğin basit tamsayılar içindir) ve parantez gerekmez.

Mantıksal ve bitsel işlemler arasındaki farklar (boolean olmayanlarda)

Bit ve mantıksal işlemlerin yalnızca boolean NumPy dizileri (ve boolean Series & DataFrames) için eşdeğer olduğunu vurgulamak gerçekten önemlidir. Bunlar boolean içermiyorsa, işlemler farklı sonuçlar verecektir. NumPy dizilerini kullanarak örnekler ekleyeceğim, ancak sonuçlar panda veri yapıları için benzer olacaktır:

>>> import numpy as np
>>> a1 = np.array([0, 0, 1, 1])
>>> a2 = np.array([0, 1, 0, 1])

>>> np.logical_and(a1, a2)
array([False, False, False,  True])
>>> np.bitwise_and(a1, a2)
array([0, 0, 0, 1], dtype=int32)

NumPy (ve benzer şekilde pandalar), boole ( Boole veya “maske” dizin dizileri ) ve tamsayı ( Dizin dizileri ) dizinleri için farklı şeyler yaptığından , dizin oluşturmanın sonuçları da farklı olacaktır:

>>> a3 = np.array([1, 2, 3, 4])

>>> a3[np.logical_and(a1, a2)]
array([4])
>>> a3[np.bitwise_and(a1, a2)]
array([1, 1, 1, 2])

Özet tablosu

Logical operator | NumPy logical function | NumPy bitwise function | Bitwise operator
-------------------------------------------------------------------------------------
       and       |  np.logical_and        | np.bitwise_and         |        &
-------------------------------------------------------------------------------------
       or        |  np.logical_or         | np.bitwise_or          |        |
-------------------------------------------------------------------------------------
                 |  np.logical_xor        | np.bitwise_xor         |        ^
-------------------------------------------------------------------------------------
       not       |  np.logical_not        | np.invert              |        ~

Nerede mantıksal operatör NumPy diziler için çalışmaz , Serisi pandas ve pandalar DataFrames. Diğerleri bu veri yapıları (ve düz Python nesneleri) üzerinde çalışır ve element olarak çalışır. Ancak bool, bool bu bağlamda tamsayı olarak yorumlanacağı için (örneğin ~Falsedöndürür -1ve ~Truedöndürür -2) düz Python'larda bitsel ters çevirmeye dikkat edin .

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.