2016-07-26 22 views
6

Zacznę 3 prostych przykładów:Dlaczego grupa nie sumuje konwersji boolean na int lub float?

pd.DataFrame([[True]]).sum() 

0 1 
dtype: int64 

pd.DataFrame([True]).sum() 

0 1 
dtype: int64 

pd.Series([True]).sum() 

1 

Wszystkie one są, jak oczekiwano. Oto bardziej skomplikowany przykład.

df = pd.DataFrame([ 
     ['a', 'A', True], 
     ['a', 'B', False], 
     ['a', 'C', True], 
     ['b', 'A', True], 
     ['b', 'B', True], 
     ['b', 'C', False], 
    ], columns=list('XYZ')) 

df.Z.sum() 

4 

Również zgodnie z oczekiwaniami. Jednak gdybym groupby(['X', 'Y']).sum()

enter image description here

spodziewałem się, że wyglądają jak:

enter image description here

myślę błąd. Czy istnieje inne wytłumaczenie?


za odpowiedź @ unutbu za

pandy próbuje przekształcić jako oryginalne dtypes. Pomyślałem, że może grupa, którą wykonałem, nie podzieliła się niczym. Próbowałem tego przykładu, aby przetestować ten pomysł.

df = pd.DataFrame([ 
     ['a', 'A', False], 
     ['a', 'B', False], 
     ['a', 'C', True], 
     ['b', 'A', False], 
     ['b', 'B', False], 
     ['b', 'C', False], 
    ], columns=list('XYZ')) 

będę groupby('X') i sum. Jeśli @unutbu jest poprawna, kwoty te powinny być 1 i 0 i są castable do bool zatem powinniśmy zobaczyć bool

df.groupby('X').sum() 

enter image description here

Rzeczywiście ... bool

Ale jeśli proces jest taki sam, ale wartości są nieco inne.

df = pd.DataFrame([ 
     ['a', 'A', True], 
     ['a', 'B', False], 
     ['a', 'C', True], 
     ['b', 'A', False], 
     ['b', 'B', False], 
     ['b', 'C', False], 
    ], columns=list('XYZ')) 

df.groupby('X').sum() 

enter image description here

lekcja. Zawsze używaj astype(int) lub czegoś podobnego, kiedy to robisz.

df.groupby('X').sum().astype(int) 

daje spójne wyniki dla każdego scenariusza.

+1

Prawdopodobnie nazwałbym to również błędem, zwłaszcza, że ​​dostajesz to, czego się spodziewasz po 'df ['Z'] = df ['Z']. Astype (int)'. Idź i zgłoś to i sprawdź, czy twórcy 'pand' mają powód takiego zachowania. –

+2

Dzieje się tak, ponieważ ['_cython_agg_blocks'] (https://github.com/pydata/pandas/blob/master/pandas/core/groupby.py#L3128) wywołuje' _try_coerce_and_cast_result', który wywołuje ['_try_cast_result'] (https: //github.com/pydata/pandas/blob/master/pandas/core/internals.py#L536), który próbuje zwrócić wynik * tego samego dtype * jako oryginalne wartości (w tym przypadku 'bool'). – unutbu

+1

@unutbu Widzę zalety tej decyzji. Wydaje się jednak, że podczas korzystania z agregacji grupowej zawsze powinniśmy rzutować jako typ, jakiego oczekujemy. Pytanie, czy mógłbyś zamieścić to jako odpowiedź, więc wydaje się, że odpowiedź została udzielona? Dzięki! – piRSquared

Odpowiedz

4

Dzieje się tak dlatego _cython_agg_blocks rozmowy _try_coerce_and_cast_result który zwraca _try_cast_result która stara się zwrócić wynik tego samego dtype co oryginalne wartości (w tym przypadku, bool).

Powoduje to zwrot czegoś, co jest trochę dziwne, gdy Z ma dtype bool (a wszystkie grupy mają nie więcej niż jedną wartość True). Jeśli którakolwiek z grup ma 2 lub więcej wartości True, wartości wynikowe są wartościami zmiennymi, ponieważ _try_cast_result nie konwertuje 2.0 powrót do wartości logicznej.

_try_cast_result robi coś bardziej użytecznego kiedy Z ma dtype int: Wewnętrznie agregator Cython wykorzystywane przez df.groupby(['X', 'Y']).sum() Zwraca result z dtype float. Tutaj następnie _try_cast_result zwraca wynik do dtype int.

Powiązane problemy