Powiedzmy, że mam dziennik aktywności użytkowników i chcę wygenerować raport o łącznym czasie trwania i liczbie unikalnych użytkowników dziennie.
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]})
Sumowanie czasu trwania jest dość proste:
group = df.groupby('date')
agg = group.aggregate({'duration': np.sum})
agg
duration
date
2013-04-01 65
2013-04-02 45
Chciałbym jednocześnie zsumować czas trwania i liczyć różne elementy, ale nie mogę znaleźć odpowiednika dla count_distinct:
agg = group.aggregate({ 'duration': np.sum, 'user_id': count_distinct})
To działa, ale na pewno jest lepszy sposób, prawda?
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 po prostu muszę zapewnić funkcję, która zwraca liczbę różnych elementów obiektu Series do funkcji agregującej, ale nie mam do dyspozycji wielu bibliotek. Wydaje się również, że obiekt groupby już zna te informacje, więc czy nie powtórzyłbym tego po prostu?
nunique
bezpośrednio. Zobacz rozwiązanie @Blodwyn Pig poniżej'nunique' jest opcją dla .agg () od pand 0.20.0, więc:
df.groupby('date').agg({'duration': 'sum', 'user_id': 'nunique'})
źródło
duration: np.unique
df.groupby('date').agg({'user_id': lambda s: s.unique().reset_index(drop=True)})
Po dodaniu do już udzielonych odpowiedzi rozwiązanie wykorzystujące ciąg
"nunique"
wydaje się znacznie szybsze, przetestowane tutaj na ~ 21 milionach wierszy dataframe, a następnie zgrupowane w ~ 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
źródło