2016-04-24 21 views
6

Ho il seguente MCVE:Espressioni con "== true" e "è vero" dare risultati diversi

#!/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]) 

L'uscita è la seguente, che mi aspettavo:

Whole DataFrame: 
    0 
    0 True 
    1 False 
    2 True 

Filtered DataFrame: 
    0 
    0 True 
    2 True 

Va bene, ma lo stile PEP8 sembra essere sbagliato, si dice: confronto E712 true dovrebbe essere if cond is True o if cond. Così ho cambiato in is True invece di == True ma ora viene a mancare, l'output è:

Whole DataFrame: 
    0 
0 True 
1 False 
2 True 

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

Che cosa sta succedendo?

+0

"Va bene, ma lo stile PEP8 sembra essere sbagliato, si dice: E712 il confronto con True dovrebbe essere se cond è True o se cond. ". WTF? PEP8 in realtà dice "Sì:' se saluta', No: 'se saluto == True', Peggio' se il saluto è True' ". –

+1

Non è preferibile 'df [df [0]]' in ogni caso? – IanS

+0

@IanS Può essere (non come leggibile IMO), ma la domanda non è su questo: ^) "Qual è la differenza tra un uomo intelligente e un uomo saggio? - Un uomo intelligente esce dai guai con i colori volanti, un l'uomo saggio non ottiene _into_ it. " –

risposta

2

Il fermo qui è che in df[df[0] == True], non sta confrontando oggetti per True.

Come dicono le altre risposte, == è sovraccarico in pandas per produrre un Series anziché un bool come fa normalmente. [] è sovraccarico, anche per interpretare Series e fornire il risultato filtrato. Il codice è sostanzialmente equivalente a:

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

Così, sei non violare PEP8 lasciando == qui.


In sostanza, pandas dà sintassi familiare semantica inusuali - che è quello che ha causato la confusione.

Accoring to Stroustroup (sez.3.3.3), l'overloading dell'operatore ha causato guai a causa di ciò sin dalla sua invenzione (e ha dovuto riflettere sodo se includerlo in C++). Seeing even more abuse of it in C++, Gosling correva all'estremo opposto di Java, mettendolo completamente al bando, e questo si è rivelato esattamente questo, un estremo.

In conclusione, linguaggi e codici moderni tendono ad avere l'overloading degli operatori, ma guardare da vicino non abusare e per la semantica di rimanere coerente.

+0

ahhh, ok, questa è una possibilità, anche se non troppo bella da leggere ;-) ... – PanchoVarallo

+1

Non penso che abbia raccomandato di usarlo. Usare '==' è perfettamente a posto. – MaxNoe

+0

Ma pycharm si lamenta se uso == True ... –

2

Penso che nel confronto pandas funzioni solo con == e il risultato sia boolean Series. Con is l'output è False. Ulteriori informazioni su 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

Ed è fatto così, perché '==' può essere ridefinito per le classi personalizzate e 'is' no. È lo stesso caso di 'SQLAlchemy' dove clausole - OP deve ignorare l'avviso o disabilitarlo con il commento' noqa'. –

+0

Grazie per il commento. – jezrael

5

In pitone, is verifica se un oggetto è uguale a un'altra. == è definito da una pandas.Series agire elemento-saggio, is non è.

A causa di ciò, df[0] is True confronta se df[0] e True sono lo stesso oggetto. Il risultato è False, che a sua volta è pari a 0, in modo da ottenere i 0 colonne quando si fa df[df[0] is True]

+0

Quindi, è fondamentalmente un bug a causa della mancanza di un sovraccarico? –

+3

Non è possibile sovraccaricare 'is'. – MaxNoe

2

Questa è un'elaborazione sulla risposta di MaxNoe poiché era troppo lungo per includere nei commenti.

Mentre indicato, df[0] is True viene valutato come False, che poi è costretto a 0 che corrisponde ad un nome di colonna. Ciò che è interessante di questo è che se si esegue

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

Questo sembra un po 'perplessi in un primo momento (almeno per me), ma ha a che fare con il modo in pandas fa uso di caching. Se si guarda a come df[False] si risolve, è sembra

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

Dal cache è solo un pitone regolare dict, dopo l'esecuzione df[0] il cache assomiglia

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

in modo che quando guardiamo in alto False, python lo costringe a 0. Se non abbiamo già innescato la cache utilizzando df[0], quindi res è None che innesca un KeyError on line 1345 di generic.py

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

questo non è veramente correlato alla domanda originale più ma molto interessante ... –