2013-09-01 9 views
48

Angenommen, ich habe ein Protokoll der Benutzeraktivität und ich möchte einen Bericht über die Gesamtdauer und die Anzahl der einzelnen Benutzer pro Tag generieren.Pandas Aggregat Anzahl ausgeprägt

import numpy as np 
import pandas as pd 
df = pd.DataFrame({'date': ['2013-04-01','2013-04-01','2013-04-01','2013-04-02', '2013-04-02'], 
    'user_id': ['0001', '0001', '0002', '0002', '0002'], 
    'duration': [30, 15, 20, 15, 30]}) 

Dauer Aggregieren ist ziemlich einfach:

group = df.groupby('date') 
agg = group.aggregate({'duration': np.sum}) 
agg 
      duration 
date 
2013-04-01  65 
2013-04-02  45 

Was ich möchte Summe zu tun ist, die Dauer und zählen distincts zur gleichen Zeit, aber ich kann nicht scheinen, ein Äquivalent für finden count_distinct:

agg = group.aggregate({ 'duration': np.sum, 'user_id': count_distinct}) 

Das funktioniert, aber es gibt einen besseren Weg, nein?

group = df.groupby('date') 
agg = group.aggregate({'duration': np.sum}) 
agg['uv'] = df.groupby('date').user_id.nunique() 
agg 
      duration uv 
date 
2013-04-01  65 2 
2013-04-02  45 1 

Ich denke, ich brauche zu schaffen, nur eine Funktion, die die Anzahl der verschiedenen Elemente einer Serie Objekt auf die Aggregatfunktion zurückgibt, aber ich weiß nicht vielen Kontakt mit den verschiedenen Bibliotheken an meinem Verfügung. Es scheint auch, dass das groupby Objekt diese Information bereits kennt, also würde ich nicht einfach Aufwand duplizieren?

Antwort

86

Wie wäre es entweder von:

>>> df 
     date duration user_id 
0 2013-04-01  30 0001 
1 2013-04-01  15 0001 
2 2013-04-01  20 0002 
3 2013-04-02  15 0002 
4 2013-04-02  30 0002 
>>> df.groupby("date").agg({"duration": np.sum, "user_id": pd.Series.nunique}) 
      duration user_id 
date       
2013-04-01  65  2 
2013-04-02  45  1 
>>> df.groupby("date").agg({"duration": np.sum, "user_id": lambda x: x.nunique()}) 
      duration user_id 
date       
2013-04-01  65  2 
2013-04-02  45  1 
+1

Das ist es. pd.Series.nunique ist, was ich nicht finden konnte, gut, konnte nicht richtig arbeiten. Ziemlich offensichtlich im Nachhinein. Vielen Dank! – dave

+1

Diese Antwort ist veraltet. Sie können jetzt 'nunique' direkt verwenden. Siehe @Blodwyn Pigs Lösung unter –

13

'Nunique' ist jetzt eine Option für .agg(), so:

df.groupby('date').agg({'duration': 'sum', 'user_id': 'nunique'}) 
+0

Ist es möglich, Agg und die einzigartigen Werte zu erhalten? etwas wie 'duration: np.unique' – guy

3

nur auf die Antworten Zugabe bereits gegeben, @Blodwyn Pig Lösung ist am effizientesten.

Diese Lösung scheint viel schneller, getestet hier auf ~ 21M Reihen Datenrahmen gruppiert dann auf ~ 2M

%time _=g.agg({"id": lambda x: x.nunique()}) 
CPU times: user 3min 3s, sys: 2.94 s, total: 3min 6s 
Wall time: 3min 20s 

%time _=g.agg({"id": pd.Series.nunique}) 
CPU times: user 3min 2s, sys: 2.44 s, total: 3min 4s 
Wall time: 3min 18s 

%time _=g.agg({"id": 'nunique'}) 
CPU times: user 14 s, sys: 4.76 s, total: 18.8 s 
Wall time: 24.4 s 
+1

Netter Fang! Ich denke, es ist b/c in einem "Lambda"/"andere Funktion" Fall wird es sequentiell angewendet, während "bekannte" Funktionen auf die gesamte Spalte in einer vektorisierten Weise angewendet werden. – Ufos