Панды выполняют повторную выборку два раза в месяц по четным месяцам

У меня есть следующие ежедневные данные:

1983-03-30    0.001224
1983-03-31   -0.003741
1983-04-04    0.005121
1983-04-05    0.009171
1983-04-06    0.006395
1983-04-07    0.009030
1983-04-08    0.006961
1983-04-11   -0.003950
1983-04-12    0.018837
1983-04-13   -0.000324
          ...

Я хотел бы выполнить повторную выборку с использованием частоты раз в два месяца. Итак, я делаю:

s.resample('2ME').agg('last')  # Use '2M' for older versions of Pandas

Это производит следующее:

1983-03-31   -0.003741
1983-05-31    0.001987
1983-07-31    0.005657
1983-09-30   -0.007843
1983-11-30   -0.005444
1984-01-31    0.003011
1984-03-31   -0.000324
1984-05-31    0.000649
1984-07-31   -0.001447
1984-09-30    0.002705

Однако я хотел бы сгруппировать (3,4), (5,6), (7,8) и т. д., поэтому мне нужна серия, в которой есть временные метки:

1983-04-30
1983-06-31
1983-08-31

Чтобы воспроизвести это:

index = pd.date_range(start='1983-03-28', end='1984-01-01', freq='B')
s = pd.Series(data=np.random.randn(len(index)), index=index)

Как я могу передать повторную выборку в группу по четным месяцам? Или, что еще лучше, при группировке всегда использовать первые два, а не первую 1, как в приведенном выше случае — март группируется сам по себе, затем апрель и май вместе, а не группируются март и апрель вместе.

Есть ли у вас возможность просто отказаться от первого месяца? Это хак, который может поставить под угрозу качество набора данных, но ваша группировка, вероятно, будет работать даже месяцы, если вы ее запустите df.iloc[2:].resample('2M').agg('last')

rma 17.05.2024 01:24

@rma Что касается предложенного вами изменения, 'ME' был добавлен в версии 2.2. См. документацию: Смещение псевдонимов

wjandrea 17.05.2024 01:49

Было бы полезно, если бы вы заполнили ГСЧ, как np.random.seed(0), чтобы результат был воспроизводимым. Для справки см. Как сделать хорошие воспроизводимые примеры панд.

wjandrea 17.05.2024 01:50
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
99
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам следует использовать closed='left':

s.resample('2M', closed='left').agg('last')

Выход:

1983-04-30    2.269755
1983-06-30    0.462782
1983-08-31    0.906045
1983-10-31   -0.098453
1983-12-31    1.336528
Freq: 2M, dtype: float64

См. документацию resample:

закрыто {'право', 'лево'}, по умолчанию Нет Какая сторона интервала интервала закрыто. По умолчанию установлено значение «влево» для всех смещений частоты, кроме «ME», «YE», «QE», «BME», «BA», «BQE» и «W», которые имеют значения по умолчанию. «правильного».

Это неправильно – окончание предыдущего периода включается в следующий период!

s5s 03.06.2024 23:51
Ответ принят как подходящий

Ответ @mozway неверен, поскольку он включает последние данные за предыдущие 2 месяца в следующие 2 месяца (например, в результаты за 30 июня он будет включать 30 апреля)! Способ сделать это таков:

np.random.seed(0)
N=365

r = pd.Series(100+np.random.randn(N), index=pd.bdate_range(start='2000-01-01', periods=N))
r = r.pct_change().dropna()
r = r.to_frame().rename(columns = {0:'r'})
r = r.reset_index().rename(columns = {'index':'date'})

r['odd_month'] = r['date'].dt.month % 2
r['grouping_date'] = r.apply(lambda x: x['date'] + DateOffset(months=x['odd_month']), axis=1).dt.strftime('%Y%m')
r['r'] +=1
r = r.groupby('grouping_date').agg({'date': 'last', 'r':'prod'}).set_index('date') - 1
r = r['r']

Выход:

date
2024-02-29    0.001835
2024-04-30   -0.007572
2024-06-28   -0.007623
2024-08-30   -0.014359
2024-10-31    0.033280
2024-12-31   -0.027050
2025-02-28    0.011792
2025-04-30   -0.005063
2025-05-23   -0.001721
Name: r, dtype: float64

Другие вопросы по теме