2016-05-22 32 views
2

Ich wollte bedingte Zählung nach groupby machen; B. nach Werten der Spalte A gruppieren und dann innerhalb jeder Gruppe zählen, wie oft der Wert 5 in der Spalte B erscheint.Bedingtes Zählen in Gruppen

Wenn ich dies für die gesamte DataFrame tat, ist es nur len(df[df['B']==5]). Also ich hoffte, ich könnte df.groupby('A')[df['B']==5].size() tun. Aber ich denke, boolesche Indizierung funktioniert nicht innerhalb GroupBy Objekte.

Beispiel:

import pandas as pd 
df = pd.DataFrame({'A': [0, 4, 0, 4, 4, 6], 'B': [5, 10, 10, 5, 5, 10]}) 
groups = df.groupby('A') 
# some more code 
# in the end, I want to get pd.Series({0: 1, 1: 2, 6: 0}) 

Antwort

5

alle Zeilen auswählen, wo B 5 entspricht, und dann gelten groupby/size:

In [43]: df.loc[df['B']==5].groupby('A').size() 
Out[43]: 
A 
0 1 
4 2 
dtype: int64 

Alternativ Sie groupby/agg mit einer benutzerdefinierten Funktion verwenden:

In [44]: df.groupby('A')['B'].agg(lambda ser: (ser==5).sum()) 
Out[44]: 
A 
0 1 
4 2 
Name: B, dtype: int64 

Beachten Sie, dass im Allgemeinenverwendenmit einer benutzerdefinierten Funktion ist langsamer als groupby mit einer integrierten Methode wie size. Also lieber die erste Option über die zweite.

In [45]: %timeit df.groupby('A')['B'].agg(lambda ser: (ser==5).sum()) 
1000 loops, best of 3: 927 µs per loop 

In [46]: %timeit df.loc[df['B']==5].groupby('A').size() 
1000 loops, best of 3: 649 µs per loop 

A Werte umfassen, in denen die Größe Null ist, könnten Sie das Ergebnis indizieren:

import pandas as pd 
df = pd.DataFrame({'A': [0, 4, 0, 4, 4, 6], 'B': [5, 10, 10, 5, 5, 10]}) 
result = df.loc[df['B'] == 5].groupby('A').size() 
result = result.reindex(df['A'].unique()) 

Ausbeuten

A 
0 1.0 
4 2.0 
6 NaN 
dtype: float64 
+0

Mit dem ersten Ansatz, verliere ich die Gruppen, in denen Die bedingte Anzahl ist Null (ich habe das Beispiel in der Frage aktualisiert, um es zu verdeutlichen). Ich weiß nicht, ob es leicht ist, es zu modifizieren, um damit fertig zu werden. Der zweite Ansatz funktioniert perfekt. – max

+0

uh .. bei meinem DataFrame dauert der erste Ansatz 41 ms, der zweite dauert 10 s! Ich denke, es ist der erste Ansatz überhaupt, nur Nullen getrennt irgendwie zu behandeln. – max

+0

@max Ich denke, die Zeitdifferenz steigt als 'df [df ['B'] == 5]' wird zu einer kleineren Teilmenge im gesamten Datenrahmen. Um mit Nullen umzugehen, können Sie die eindeutigen Elemente aus Spalte A mit 'a = df [" A "]. Unique()' erhalten und dann map mit dem ersten Ansatz verwenden: 'pd.Series (a, index = a) .map (df.loc [df ['B'] == 5] .groupby ('A'). size()). fillna (0) 'Natürlich kann es nicht so schnell sein wie der erste Ansatz, aber es sollte immer noch viel schneller als agg/lambda. – ayhan