2013-09-01 11 views
48

Załóżmy, że mam dziennik aktywności użytkowników i chcę wygenerować raport o łącznym czasie trwania i liczbie unikalnych użytkowników dziennie.Liczba agregatów pand odrębna

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]}) 

Agregacja trwania jest dość prosta:

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

Co chciałbym zrobić, to suma czasu trwania i liczyć distincts w tym samym czasie, ale nie wydaje się znaleźć odpowiednik dla count_distinct:

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

To działa, ale na pewno jest lepszy sposób, nie?

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 

myślę, że wystarczy, aby zapewnić funkcję zwracającą liczbę odrębnych elementów obiektu szeregowo z funkcji zbiorczej, ale nie mam wiele ekspozycji do różnych bibliotek w moim sprzedaż. Wydaje się również, że obiekt Groupby już zna tę informację, więc czy nie powieliłbym tylko wysiłku?

Odpowiedz

86

Jak o jedno z:

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

To wszystko. pd.Series.nunique jest tym, czego nie mogłem znaleźć, cóż, nie mógłbym poprawnie działać. Dość oczywiste z perspektywy czasu. Dzięki! – dave

+1

Ta odpowiedź jest nieaktualna. Możesz teraz użyć 'nunique' bezpośrednio. Zobacz rozwiązanie @Blodwyn Pig poniżej –

13

'nunique' jest teraz opcja dla .agg(), więc:

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

Czy jest możliwe, aby ag i uzyskać unikalne wartości? coś w stylu 'duration: np.unique' – guy

3

Wystarczy dodanie do już udzielonych odpowiedzi, rozwiązania @Blodwyn Pig jest najbardziej wydajny.

Rozwiązanie to wydaje się o wiele szybciej, testowany tutaj na ~ 21m dataframe wierszy, a następnie grupowane do ~ 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

Fajny połów! Przypuszczam, że jest to b/cw przypadku "lambda"/"inna funkcja", jest ono stosowane sekwencyjnie, a "znane" funkcje są stosowane do całej kolumny w wektoryzacji. – Ufos