Общее количество панд различно

95

Допустим, у меня есть журнал активности пользователей, и я хочу создать отчет с общей продолжительностью и количеством уникальных пользователей за день.

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

Что я хотел бы сделать, так это просуммировать продолжительность и подсчитать различия одновременно, но я не могу найти эквивалент для 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

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

Дэйв
источник

Ответы:

156

Как насчет любого из:

>>> 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
DSM
источник
1
Вот и все. pd.Series.nunique - это то, что я не смог найти, ну, не смог заставить работать правильно. Оглядываясь назад, довольно очевидно. Благодарность!
Дэйв
5
Этот ответ устарел. Теперь вы можете использовать nuniqueнапрямую. См. Решение @Blodwyn Pig ниже
Тед
Спасибо @TedPetrou, я - кодер, ранее известный как Blodwyn Pig;)
Рикки Макмастер
Эй, вы знаете, как получить неповторяющийся счет?
Амблеу
62

nunique - это опция для .agg (), начиная с pandas 0.20.0, поэтому:

df.groupby('date').agg({'duration': 'sum', 'user_id': 'nunique'})
Рики Макмастер
источник
Можно ли объединить и получить уникальные значения? что-то вродеduration: np.unique
парень
@guy Попробуйтеdf.groupby('date').agg({'user_id': lambda s: s.unique().reset_index(drop=True)})
BallpointBen
Как нам получить результат?
17

Просто добавив к уже приведенным ответам, решение, использующее строку, "nunique"кажется намного быстрее, протестировано здесь на кадре данных ~ 21 млн строк, а затем сгруппировано в ~ 2 млн

%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
user6903745
источник
1
Хорошо поймал! Я предполагаю, что это b / c в случае «лямбда» / «другая функция», оно применяется последовательно, в то время как «известные» функции применяются ко всему столбцу векторизованным способом.
Ufos
какое решение от @Blodwyn Pig?
Chogg
@Chogg, самый быстрый!
m-dz
@Chogg - извините, я изменил свое имя пользователя. Это был я.
Рики Макмастер