Управление меткой последней строки при группировке кадра данных с использованием pandas Grouper - PullRequest
2 голосов
/ 17 апреля 2020

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

import random
import pandas as pd

n_rows = 100
df = pd.DataFrame({"date": pd.date_range(periods=n_rows, end='2020-04-15'), "a": range(n_rows)})
aggregated = df.groupby(pd.Grouper(key="date", freq="30D")).sum().reset_index()

print(aggregated.date.max()) 
# out: Timestamp('2020-04-06 00:00:00')

Самая последняя дата aggregates изменяется в зависимости от n_rows: я хочу всегда быть последней датой исходного кадра данных, так что последним периодом является («2020-04-15» - 30D, «2020-04-15»). Я бы получил:

print(aggregated.date.max()) 
# out: Timestamp('2020-04-15 00:00:00')

Поскольку меня интересуют самые последние группы, мне все равно, как строится первая (самая старая) группа.

Я пробовал комбинации параметров label, closed, convention, loffset, base (документация введите описание ссылки здесь ), но я не могу найти рабочее решение: - Мой первый подход был попыткой сделать верные периоды строятся в правильном направлении, используя label="right" и closed="right" и convention, но ничего не работает:

aggregated = df.groupby(pd.Grouper(key="date", freq="30D", label="right", closed="right")).sum().reset_index()

print(aggregated.date.max()) 
# out: Timestamp('2020-04-16 00:00:00')
  • Во-вторых, я попытался сместить группы, не влияя на происхождение date, используя параметры loffset=f"{n_rows % 30}D" и / или base=+/- n_rows % 30, все еще ничего.
  • Наконец я попытался создать пользовательский объект DateOffset, но не смог найти рабочий пример с Grouper.

Теперь мне интересно, возможно ли это, и с тех пор я немного удивлен.

Любое предложение или аналогичный пример, на который я мог бы взглянуть?

Спасибо!

1 Ответ

2 голосов
/ 17 апреля 2020

С resample вам нужно использовать аргумент base, чтобы сместить ячейки. Мы можем использовать некоторое деление остатка всего временного промежутка с частотой, чтобы определить, каким оно должно быть. Затем мы выбираем правильную метку и закрываем справа (так как это 30D от самой последней)

base=((df.date.max()-df.date.min())%pd.Timedelta('30D')).days
df.resample('30D', on='date', base=base ,label='right', closed='right').sum()

               a
date            
2020-01-16    45
2020-02-15   735
2020-03-16  1635
2020-04-15  2535


#Similarly with a `pd.Grouper`
df.groupby(pd.Grouper(freq='30D', key='date', base=base ,label='right', closed='right')).sum()

Если вы готовы отказаться от resample, вы можете сделать несколько базовых c математика и использовать groupby. Мы сформируем 30-дневные группы с самой последней даты и затем агрегируем

grps = (df.date-df.date.max()-pd.Timedelta(days=1)).dt.floor('30D')
df.groupby(grps).agg({'date': 'last', 'a': 'sum'})

                date     a
date                      
-120 days 2020-01-16    45
-90 days  2020-02-15   735
-60 days  2020-03-16  1635
-30 days  2020-04-15  2535
...