pandalar: veri çerçevesi indekslenirken birden çok koşul - beklenmeyen davranış


135

Veri çerçevesindeki satırları iki sütundaki değerlere göre filtreliyorum.

Bazı nedenlerden dolayı OR operatörü, AND operatörünün davranmasını beklediğim gibi davranıyor ve bunun tersi de geçerli.

Test kodum:

import pandas as pd

df = pd.DataFrame({'a': range(5), 'b': range(5) })

# let's insert some -1 values
df['a'][1] = -1
df['b'][1] = -1
df['a'][3] = -1
df['b'][4] = -1

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a != -1) | (df.b != -1)]

print pd.concat([df, df1, df2], axis=1,
                keys = [ 'original df', 'using AND (&)', 'using OR (|)',])

Ve sonuç:

      original df      using AND (&)      using OR (|)    
             a  b              a   b             a   b
0            0  0              0   0             0   0
1           -1 -1            NaN NaN           NaN NaN
2            2  2              2   2             2   2
3           -1  3            NaN NaN            -1   3
4            4 -1            NaN NaN             4  -1

[5 rows x 6 columns]

Gördüğünüz gibi, ANDoperatör en az bir değerin eşit olduğu her satırı bırakır -1. Öte yandan, ORoperatör -1onları düşürmek için her iki değerin de eşit olmasını gerektirir . Tam tersi bir sonuç beklerdim. Biri bu davranışı açıklayabilir mi lütfen?

Pandalar 0.13.1 kullanıyorum.


1
df.queryve pd.evalbu kullanım durumu için uygun görünüyor. pd.eval()İşlevler ailesi, özellikleri ve kullanım durumları hakkında bilgi için lütfen pd.eval () kullanarak pandalarda Dinamik İfade Değerlendirmesini ziyaret edin .
cs95

Yanıtlar:


211

Gördüğünüz gibi AND operatörü, en az bir değerin -1'e eşit olduğu her satırı bırakır. Öte yandan, OR operatörü, onları bırakmak için her iki değerin de -1'e eşit olmasını gerektirir.

Doğru. Durumu bırakmak istedikleriniz açısından değil, saklamak istedikleriniz açısından yazdığınızı unutmayın . Şunun için df1:

df1 = df[(df.a != -1) & (df.b != -1)]

" df.a-1 olmayan ve -1 olmayan satırları koru" diyorsunuz df.b, bu da en az bir değerin -1 olduğu her satırı düşürmekle aynıdır.

Şunun için df2:

df2 = df[(df.a != -1) | (df.b != -1)]

" -1 olan df.aveya df.bolmayan satırları koru" diyorsunuz , bu, her iki değerin de -1 olduğu satırları düşürmekle aynıdır.

Not: zincirleme erişim df['a'][1] = -1, başınızı belaya sokabilir. .locVe kullanma alışkanlığı kazanmak daha iyidir .iloc.


24
DataFrame.query()burada da güzel çalışıyor. df.query('a != -1 or b != -1').
Phillip Cloud

6
Pandalar yüzden istiyor biliyor &ve |üzerinde andve or?
ocaklar

3
@stoves: normal Python kodunda andve ordeğiştirilemeyen temel Python semantiğine sahip. &ve |diğer yandan, davranışlarını kontrol eden ilgili özel yöntemlere sahiptir. (Sorgu dizelerinde, elbette, istediğimiz herhangi bir ayrıştırmayı uygulamakta özgürüz.)
DSM

ilginç bir şekilde, df[True & False]başarısız gibi görünüyor ancak df[(True) & (False)]başarılı oluyor (bu örnekte test edilmedi)
3pitt

1
Bu tür bir sözdizimini birden çok satıra bölmek mümkün olabilir mi? Çoğu PEP8 ne olurdu?
tommy.carstensen

42

Sorgu () kullanabilirsiniz , yani:

df_filtered = df.query('a == 4 & b != 2')

Bu sözdiziminin daha mantıklı olduğunu düşündüğüm bir durum var, örneğin: df.query ('' (a == 4 & b! = 2) | c == 3 ")
Aus_10

9

Burada biraz matematiksel mantık teorisi :

"NOT a AND NOT b" , "NOT (a OR b)" ile aynıdır , bu nedenle:

"Bir değil -1 ve b -1" eşdeğer "(a, 1 ya da b -1)" ters arasında (tamamlayıcı) olan, "(a, 1 ya da b-1)" .

Dolayısıyla, tam tersi sonuç istiyorsanız, df1 ve df2 aşağıdaki gibi olmalıdır:

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a == -1) | (df.b == -1)]
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.