Il conteggio complessivo dei panda è distinto


94

Diciamo che ho un registro delle attività degli utenti e voglio generare un rapporto sulla durata totale e sul numero di utenti unici al giorno.

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

La durata dell'aggregazione è piuttosto semplice:

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

Quello che vorrei fare è sommare la durata e contare i distinti allo stesso tempo, ma non riesco a trovare un equivalente per count_distinct:

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

Funziona, ma sicuramente c'è un modo migliore, no?

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

Penso di dover solo fornire una funzione che restituisca il conteggio di elementi distinti di un oggetto Series alla funzione aggregata, ma non ho molta esposizione alle varie librerie a mia disposizione. Inoltre, sembra che l'oggetto groupby conosca già queste informazioni, quindi non dovrei semplicemente duplicare lo sforzo?

Risposte:


156

Che ne dici di uno di questi:

>>> 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
Questo è tutto. pd.Series.nunique è ciò che non sono riuscito a trovare, beh, non riuscivo a funzionare correttamente. Abbastanza ovvio col senno di poi. Grazie!
dave

5
Questa risposta è obsoleta. Ora puoi usare nuniquedirettamente. Vedi la soluzione di @Blodwyn Pig di seguito
Ted Petrou

Grazie @TedPetrou, io sono il programmatore precedentemente noto come Blodwyn Pig;)
Ricky McMaster

Ehi, sai come ottenere un conteggio non duplicato?
Ambleu

61

'nunique' è un'opzione per .agg () a partire da pandas 0.20.0, quindi:

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

È possibile agg e ottenere i valori univoci? qualcosa comeduration: np.unique
ragazzo

@guy Trydf.groupby('date').agg({'user_id': lambda s: s.unique().reset_index(drop=True)})
BallpointBen

Come otteniamo l'output?

17

Aggiungendo solo le risposte già fornite, la soluzione che utilizza la stringa "nunique"sembra molto più veloce, testata qui su ~ 21 milioni di righe di dataframe, quindi raggruppata in ~ 2 milioni

%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
Bella presa! Immagino che sia b / c in un caso "lambda" / "altra funzione" viene applicato sequenzialmente, mentre le funzioni "note" vengono applicate all'intera colonna in modo vettorializzato.
UFO

quale soluzione è di @Blodwyn Pig?
Chogg

@Chogg, il più veloce!
m-dz

@Chogg - scusa se ho cambiato il mio nome utente. Ero io.
Ricky McMaster
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.