2013-09-01 3 views
48

Предположим, у меня есть журнал активности пользователя, и я хочу сгенерировать отчет общей продолжительности и количества уникальных пользователей в день.Pandas aggregate count distinct

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

Агрегирование длительности довольно прост:

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

То, что я хотел бы сделать, это сумма продолжительности и подсчитывать distincts в то же самое время, но я не могу найти эквивалент для count_distinct:

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

Это работает, но, безусловно, есть лучший способ, нет?

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 

Я думаю, мне просто нужно, чтобы обеспечить функцию, которая возвращает количество различных элементов объекта серии к агрегатной функции, но у меня нет много воздействия различных библиотек на моем удаление. Кроме того, кажется, что объект groupby уже знает эту информацию, так что я бы просто не дублировал усилия?

ответ

86

Как о любом из:

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

Вот так. pd.Series.nunique - это то, чего я не смог найти, ну, не мог нормально работать. Довольно очевидно, оглядываясь назад. Благодаря! – dave

+1

Этот ответ устарел. Теперь вы можете использовать 'nunique' напрямую. См. Решение @Blodwyn Pig ниже –

13

'nunique' теперь вариант для .agg(), так что:

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

Возможно ли получить агг и получить уникальные значения? что-то вроде 'duration: np.unique' – guy

3

Просто добавив к ответам уже данным, @Blodwyn Свиньи решения является наиболее эффективным.

Это решение кажется намного быстрее, здесь испытывались на ~ 21М строк dataframe, затем группируются в ~ 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

Хороший улов! Я предполагаю, что это b/c в случае «лямбда»/«другой функции», он применяется последовательно, а «известные» функции применяются ко всему столбцу векторизованным образом. – Ufos