2016-04-24 11 views
6

Ich habe folgendes MCVE:Ausdrücke mit "== True" und "True" geben unterschiedliche Ergebnisse

#!/usr/bin/env python3           

import pandas as pd 

df = pd.DataFrame([True, False, True]) 

print("Whole DataFrame:") 
print(df) 

print("\nFiltered DataFrame:") 
print(df[df[0] == True]) 

Der Ausgang ist die folgende, die ich erwartet hatte:

Whole DataFrame: 
    0 
    0 True 
    1 False 
    2 True 

Filtered DataFrame: 
    0 
    0 True 
    2 True 

Okay, aber der PEP8 Stil scheint falsch zu sein, es heißt: E712 Vergleich zu True sollte if cond is True oder if cond sein. So habe ich es zu is True statt == True aber jetzt schlägt es, der Ausgang ist:

Whole DataFrame: 
    0 
0 True 
1 False 
2 True 

Filtered DataFrame: 
0  True 
1 False 
2  True 
Name: 0, dtype: bool 

Was ist los?

+0

„Okay, aber die PEP8 Stil falsch zu sein scheint, heißt es: E712 Der Vergleich zu True sollte erfolgen, wenn cond True oder if cond. ist. WTF? PEP8 sagt eigentlich "Ja:' wenn Begrüßung ", Nein:' wenn Begrüßung == Wahr ', Schlechter 'wenn Begrüßung Wahr ist". –

+1

Ist 'df [df [0]] 'in keinem Fall vorzuziehen? – IanS

+0

@IanS Es mag sein (nicht als lesbare IMO), aber die Frage ist nicht etwa: ^) "Was ist der Unterschied zwischen einem klugen Mann und einem weisen Mann? - Ein kluger Mann kommt aus allen Schwierigkeiten mit Bravour, a Der weise Mann bekommt es nicht. –

Antwort

2

Der Haken dabei ist, zu tun, dass in df[df[0] == True], Sie sind nicht Objekte True zu vergleichen.

Wie die anderen Antworten sagen, ist == in pandas überlastet ein produzieren Series anstelle eines bool, wie es normalerweise der Fall ist. [] ist auch überladen, um die Series zu interpretieren und das gefilterte Ergebnis zu geben. Der Code ist im Wesentlichen äquivalent zu:

series = df[0].__eq__(True) 
df.__getitem__(series) 

Sie sind also nicht PEP8 Verletzung von == hier zu verlassen.


Im Wesentlichen gibt pandas bekannte Syntax ungewöhnliche Semantik - das ist es, was die Verwirrung verursacht.

Accoring to Stroustroup (sec.3.3.3), hat die Überlastung des Operators seit seiner Erfindung zu Problemen geführt (und er musste darüber nachdenken, ob er in C++ aufgenommen werden sollte). Seeing even more abuse of it in C++, lief Gosling in Java auf das andere Extrem und verbot es komplett, und das war genau das, ein Extrem.

Als eine Schlussfolgerung tendieren moderne Sprachen und Code dazu, Operatorüberladung zu haben, aber passen Sie genau auf, um es nicht übermäßig zu verwenden, und damit Semantik konsistent bleibt.

+0

ahhh, okay, das ist eine Möglichkeit, obwohl nicht zu schön zu lesen ;-) ... – PanchoVarallo

+1

Ich glaube nicht, dass er empfohlen hat, das zu benutzen. Die Verwendung von '==' ist völlig in Ordnung. – MaxNoe

+0

Aber pycharm collis wenn ich == Wahre ... –

2

Ich denke, in pandas Vergleich funktioniert nur mit == und das Ergebnis ist boolean Series. Mit is ist der Ausgang False. Weitere Informationen über is.

print df[0] == True 
0  True 
1 False 
2  True 
Name: 0, dtype: bool 

print df[df[0]] 
     0 
0 True 
2 True 

print df[df[0] == True] 
     0 
0 True 
2 True 

print df[0] is True 
False 

print df[df[0] is True] 
0  True 
1 False 
2  True 
Name: 0, dtype: bool 
+0

Und es ist so gemacht, weil '==' kann für benutzerdefinierte Klassen neu definiert werden und "ist" kann nicht. Es ist der gleiche Fall wie 'SQLAlchemy', wo Klauseln - OP die Warnung entweder ignorieren oder sie mit' noqa'-Kommentar deaktivieren muss. –

+0

Vielen Dank für Ihren Kommentar. – jezrael

5

In Python is Tests, wenn ein Objekt das gleiche wie das andere. == ist definiert durch eine pandas.Series Element-weise zu handeln, is ist nicht.

Daher df[0] is True vergleicht, wenn df[0] und True das gleiche Objekt sind. Das Ergebnis ist False, die wiederum gleich 0, so erhalten Sie die 0 Spalten, wenn df[df[0] is True]

+0

Also, es ist im Grunde ein Bug aufgrund einer fehlenden Überladung? –

+3

Sie können 'is' nicht überladen. – MaxNoe

2

Dies ist eine Ausarbeitung auf MaxNoes Antwort, da dies zu lang war, um in den Kommentaren zu enthalten.

Wie er angegeben, wertet df[0] is True-False, die dann zu 0 dazu gezwungen wird, die zu einem Spaltennamen entspricht. Was ist das interessant ist, ist , dass, wenn Sie

laufen
>>>df = pd.DataFrame([True, False, True]) 
>>>df[False] 
KeyError         Traceback (most recent call last) 
<ipython-input-21-62b48754461f> in <module>() 
----> 1 df[False] 

>>>df[0] 
0  True 
1 False 
2  True 
Name: 0, dtype: bool 
>>>df[False] 
0  True 
1 False 
2  True 
Name: 0, dtype: bool 

Diese zunächst etwas verwirrend scheint (zumindest für mich), aber hat damit zu tun, wie pandas Einsatz von Caching macht. Wenn man sich anschaut, wie df[False] behoben ist, es aussieht

/home/matthew/anaconda/lib/python2.7/site-packages/pandas/core/frame.py(1975)__getitem__() 
-> return self._getitem_column(key) 
    /home/matthew/anaconda/lib/python2.7/site-packages/pandas/core/frame.py(1999)_getitem_column() 
-> return self._get_item_cache(key) 
> /home/matthew/anaconda/lib/python2.7/site-packages/pandas/core/generic.py(1343)_get_item_cache() 
-> res = cache.get(item) 

Da cache nur ein ganz normaler Python ist dict, nach dem Ausführen df[0] der cache sieht aus wie

>>>cache 
{0: 0  True 
1 False 
2  True 
Name: 0, dtype: bool} 

so, dass, wenn wir aufschauen False, erzwingt Python dies zu 0. Wenn wir nicht bereits den Cache grundiert df[0] verwenden, dann resNone ist, die eine KeyError auf Leitung 1345 von generic.py

löst
def _get_item_cache(self, item): 
1341   """Return the cached item, item represents a label indexer.""" 
1342   cache = self._item_cache 
1343 ->   res = cache.get(item) 
1344   if res is None: 
1345    values = self._data.get(item) 
+0

Dies ist nicht wirklich auf die ursprüngliche Frage mehr, aber sehr interessant ... –