Подтвердить что ты не робот

Pandas: повторные таймеры с groupby

Учитывая ниже pandas DataFrame:

In [115]: times = pd.to_datetime(pd.Series(['2014-08-25 21:00:00','2014-08-25 21:04:00',
                                            '2014-08-25 22:07:00','2014-08-25 22:09:00']))
          locations = ['HK', 'LDN', 'LDN', 'LDN']
          event = ['foo', 'bar', 'baz', 'qux']
          df = pd.DataFrame({'Location': locations,
                             'Event': event}, index=times)
          df
Out[115]:
                               Event Location
          2014-08-25 21:00:00  foo   HK
          2014-08-25 21:04:00  bar   LDN
          2014-08-25 22:07:00  baz   LDN
          2014-08-25 22:09:00  qux   LDN

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

Out[115]:
                               HK    LDN
          2014-08-25 21:00:00  1     1
          2014-08-25 22:00:00  0     2

Я пробовал различные комбинации resample() и groupby(), но не повезло. Как я могу это сделать?

4b9b3361

Ответ 1

В своем оригинальном сообщении я предложил использовать pd.TimeGrouper. В настоящее время используйте pd.Grouper вместо pd.TimeGrouper. Синтаксис в основном такой же, но TimeGrouper теперь не рекомендуется в пользу pd.Grouper.

Более того, хотя pd.TimeGrouper может группировать только по DatetimeIndex, pd.Grouper может группировать по столбцам datetime, которые можно указать с помощью параметра key.


Вы можете использовать pd.Grouper, чтобы сгруппировать фрейм данных DatetimeIndex по часам:

grouper = df.groupby([pd.Grouper(freq='1H'), 'Location'])

используйте count для подсчета количества событий в каждой группе:

grouper['Event'].count()
#                      Location
# 2014-08-25 21:00:00  HK          1
#                      LDN         1
# 2014-08-25 22:00:00  LDN         2
# Name: Event, dtype: int64

используйте unstack, чтобы переместить уровень индекса Location на уровень столбца:

grouper['Event'].count().unstack()
# Out[49]: 
# Location             HK  LDN
# 2014-08-25 21:00:00   1    1
# 2014-08-25 22:00:00 NaN    2

а затем используйте fillna, чтобы изменить NaN на нули.


Собираем все вместе,

grouper = df.groupby([pd.Grouper(freq='1H'), 'Location'])
result = grouper['Event'].count().unstack('Location').fillna(0)

дает

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2

Ответ 2

Pandas 0,21 ответ: TimeGrouper устаревает

Для этого есть два варианта. Фактически они могут давать разные результаты на основе ваших данных. Первые группы опций по местоположению и внутри группы местоположения по часам. Вторая группа вариантов по местоположению и часу в то же время.

Вариант 1: используйте groupby + resample

grouped = df.groupby('Location').resample('H')['Event'].count()

Вариант 2: группируйте местоположение и DatetimeIndex вместе с groupby(pd.Grouper)

grouped = df.groupby(['Location', pd.Grouper(freq='H')])['Event'].count()

Они оба приведут к следующему:

Location                     
HK        2014-08-25 21:00:00    1
LDN       2014-08-25 21:00:00    1
          2014-08-25 22:00:00    2
Name: Event, dtype: int64

И затем измените форму:

grouped.unstack('Location', fill_value=0)

Выведет

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2

Ответ 3

Группировка по нескольким столбцам

Untubu точно отвечает своим ответом, но я хотел бы добавить, что вы могли бы сделать, если бы у вас был третий столбец, скажем, Cost и вы хотите объединить его, как указано выше. Именно благодаря объединению ответов unutbu и этого я узнал, как это сделать, и подумал, что поделюсь этим для будущих пользователей.

Создайте столбец DataFrame with Cost:

In[1]:
import pandas as pd
import numpy as np
times = pd.to_datetime([
    "2014-08-25 21:00:00", "2014-08-25 21:04:00",
    "2014-08-25 22:07:00", "2014-08-25 22:09:00"
])
df = pd.DataFrame({
    "Location": ["HK", "LDN", "LDN", "LDN"],
    "Event":    ["foo", "bar", "baz", "qux"],
    "Cost":     [20, 24, 34, 52]
}, index = times)
df

Out[1]:
                     Location  Event  Cost
2014-08-25 21:00:00        HK    foo    20
2014-08-25 21:04:00       LDN    bar    24
2014-08-25 22:07:00       LDN    baz    34
2014-08-25 22:09:00       LDN    qux    52

Теперь мы группируем с помощью функции agg чтобы указать метод агрегации каждого столбца, например, count, mean, sum и т.д.

In[2]:
grp = df.groupby([pd.Grouper(freq = "1H"), "Location"]) \
      .agg({"Event": np.size, "Cost": np.mean})
grp

Out[2]:
                               Event  Cost
                     Location
2014-08-25 21:00:00  HK            1    20
                     LDN           1    24
2014-08-25 22:00:00  LDN           2    43

Затем окончательный unstack с заполнением NaN нулями и отображать как int потому что это приятно.

In[3]: 
grp.unstack().fillna(0).astype(int)

Out[3]:
                    Event     Cost
Location               HK LDN   HK LDN
2014-08-25 21:00:00     1   1   20  24
2014-08-25 22:00:00     0   2    0  43

Ответ 4

Это можно сделать без использования resample или Grouper следующим образом:

df.groupby([df.index.floor("1H"), "Location"]).count()