Помощь с группировкой и агрегированием pandas

Есть данные:

data = [[1,1,1, 10],[1,1,3, 11],[1,1,4, 5],[1,2,3, 10],[1,2,20, 15],[1,2,23, 3],[2,1,1, 8],[2,1,3, 10]]
df = pd.DataFrame(data=data, index=None, columns=['mont', 'day', 'hour', 'price'])

У меня не получается следующие: Сгруппировать по месяцу и дням, найти час в котором был максимум цены в течении одного дня и вывести количество максимумов у каждого часа.

В конце получить таблицу в виде:

   | час   | количество случаев когда цена была максимальная за все дни в данном часу |
    hour    total_count
    3       2
    20      1

Я делаю следующие:

df.groupby(['mont', 'day'])['price'].max()

mont  day  price
1     1      11
      2      15
2     1      10

Но мне нужно узнать час в котором был максимум, для того чтобы сложить их количество.


Ответы (2 шт):

Автор решения: Алексей Р

Можно обойтись без max(), сразу отсортировав по цене. Потом последовательно две группировки, после первой выбираем наибольшие значения цены как последние строки в группах (сортировали ранее по возрастанию), после второй просто считаем количество строк (часов) в группах.

data = [[1, 1, 1, 10], [1, 1, 3, 11], [1, 1, 4, 5], [1, 2, 3, 10], [1, 2, 20, 15], [1, 2, 23, 3], [2, 1, 1, 8], [2, 1, 3, 10]]
df = pd.DataFrame(data=data, index=None, columns=['mont', 'day', 'hour', 'price'])
print(df.sort_values('price').groupby(['mont', 'day'], sort=False).last().groupby('hour', as_index=False).count().rename(columns={'price': 'total_count'}))
   hour  total_count
0     3            2
1    20            1
→ Ссылка
Автор решения: Kirill Kondratenko

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

idx = df.groupby(['mont', 'day'])['price'].transform(max) == df['price']
df = df[idx].groupby('hour', as_index=False)['price'].count().rename(
    columns={'price': 'total_count'})
print(df)

Вывод:

   hour  total_count
0     3            2
1    20            1
→ Ссылка