142 votes

Pandas aggregate count distinct

Disons que je dispose d'un journal de l'activité des utilisateurs et que je souhaite générer un rapport sur la durée totale et le nombre d'utilisateurs uniques par jour.

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

L'agrégation de la durée est assez simple :

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

Ce que j'aimerais faire, c'est additionner la durée et compter les distincts en même temps, mais je n'arrive pas à trouver un équivalent pour count_distinct :

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

Cela fonctionne, mais il y a sûrement un meilleur moyen, non ?

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

Je pense que je dois simplement fournir une fonction qui renvoie le nombre d'éléments distincts d'un objet Series à la fonction aggregate, mais je n'ai pas beaucoup d'expérience des différentes bibliothèques à ma disposition. De plus, il semble que l'objet groupby connaisse déjà cette information, alors ne ferais-je pas simplement double emploi ?

216voto

DSM Points 71975

Que diriez-vous de l'un ou l'autre :

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

108voto

Ricky McMaster Points 1267

Nunique' est une option pour .agg() depuis pandas 0.20.0, donc :

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

37voto

user6903745 Points 1296

En complément des réponses déjà données, la solution utilisant la chaîne de caractères "nunique" semble beaucoup plus rapide, testé ici sur un cadre de données de ~21M lignes, puis groupé à ~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

0voto

Mykola Zotko Points 1929

Si vous souhaitez obtenir uniquement un certain nombre de valeurs distinctes par groupe, vous pouvez utiliser la méthode nunique directement avec le DataFrameGroupBy objet :

df.groupby('date')['user_id'].nunique()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X