2016-07-26 5 views
6

Ich werde mit drei einfachen Beispielen beginnen:Warum konvertiert groupby sum nicht boolean in int oder float?

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

0 1 
dtype: int64 

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

0 1 
dtype: int64 

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

1 

Alle diese wie erwartet sind. Hier ist ein komplizierteres Beispiel.

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 

auch wie erwartet. Allerdings, wenn ich groupby(['X', 'Y']).sum()

enter image description here

ich es erwartet wie folgt aussehen:

enter image description here

Ich denke Fehler. Gibt es eine andere Erklärung?


Pro @ unutbu Antwort

Pandas versucht, so original dtypes neu zu fassen. Ich hatte gedacht, dass die Gruppe, in der ich aufgetreten war, vielleicht nicht wirklich etwas zusammen gefasst hatte. Also habe ich dieses Beispiel ausprobiert, um die Idee zu testen.

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

Ich werde groupby('X') und sum. Wenn @unutbu korrekt ist, sollten diese Summen 1 und 0 sein und sind gießbare zu bool, deshalb sollten wir bool

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

enter image description here

Sicher genug ... bool

Aber wenn der Prozess sehen ist das gleiche, aber die Werte sind etwas anders.

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

Lektion gelernt. Verwenden Sie immer astype(int) oder etwas ähnliches, wenn Sie dies tun.

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

gibt konsistente Ergebnisse für beide Szenarien.

+1

Ich würde es wahrscheinlich auch einen Fehler nennen, vor allem, weil Sie bekommen, was Sie erwarten nach 'df [' Z '] = df [' Z ']. Astype (int) '. Geh und berichte, ob die Entwickler von 'Pandas' einen Grund für dieses Verhalten haben. –

+2

Dies geschieht, weil ['_cython_agg_blocks] (https://github.com/pydata/pandas/blob/master/pandas/core/groupby.py#L3128)' _try_coerce_and_cast_result' aufruft, das ['_try_cast_result'] aufruft (https: //github.com/pydata/pandas/blob/master/pandas/core/internals.py#L536), die versucht, ein Ergebnis * des gleichen dtype * wie die ursprünglichen Werte (in diesem Fall 'bool') zurückzugeben. – unutbu

+1

@unutbu Ich kann den Verdienst dieser Entscheidung sehen. Dies scheint jedoch zu implizieren, dass bei der Verwendung von Gruppenaggregation immer der erwartete Typ verwendet werden sollte. Frage, könntest du das als Antwort posten, damit es als beantwortet erscheint? Danke! – piRSquared

Antwort

4

Dies geschieht, weil _cython_agg_blocks Anrufe _try_coerce_and_cast_result die _try_cast_result nennt, die ein Ergebnis des gleichen dtype wie die ursprünglichen Werte zurück versucht (in diesem Fall bool).

Dies gibt etwas seltsam zurück, wenn Z dtype bool hat (und alle Gruppen haben nicht mehr als einen True-Wert). Wenn eine der Gruppen 2 oder mehr True-Werte aufweist, sind die resultierenden Werte Floats, da _try_cast_result 2 nicht konvertiert.0 zurück zu einem booleschen Wert.

_try_cast_result macht etwas mehr nützlich, wenn Z hat dtype int: Intern der Aggregator Cython verwendet von df.groupby(['X', 'Y']).sum() kehrt ein result von dtype float. Hier gibt _try_cast_result das Ergebnis an dtype int zurück.