Pandas привязывает индекс даты и времени к определенному часу в день

#python #pandas #datetime

#python #pandas #дата и время

Вопрос:

У меня есть индекс даты и времени, который я хотел бы округлить (ceil) до определенного часа в день. Я уже знаю о псевдонимах смещения pandas и о том, как они работают, но, в частности, я хотел бы сказать, чтобы он округлял дату и время до определенного часа в день (или определенного дня в месяце). Например, я хотел бы иметь такое преобразование:

 print(results.index)
DatetimeIndex(['2018-12-14 05:00:00 01:00', '2018-12-14 06:00:00 01:00',
           '2018-12-14 07:00:00 01:00', '2018-12-14 08:00:00 01:00',
           '2018-12-14 09:00:00 01:00', '2018-12-14 10:00:00 01:00',
           '2018-12-14 11:00:00 01:00', '2018-12-14 12:00:00 01:00',
           '2018-12-14 13:00:00 01:00', '2018-12-14 14:00:00 01:00',
  

Превращается в

 DatetimeIndex(['2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
           '2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
           '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
           '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
           '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
  

Насколько мне известно, не существует такого параметра, который мы могли бы передать в ceil(), который позволил бы это, поскольку мы можем округлять только до ближайшего часа, дня, месяца (freq = ‘H’, ‘D’, ‘M’)…
Есть ли элегантное решение для этого или мне придется кодировать свой собственный цикл for?

Комментарии:

1. Если вам просто нужен определенный час для каждой даты, почему бы не использовать replace ?

Ответ №1:

Одна из идей заключается в использовании numpy.where и offsets.DateOffset — здесь hour без s средств, устанавливающих значения 8 , day со s средствами, добавляющими один день к исходным дням:

 d = pd.DatetimeIndex(['2018-12-14 05:00:00 01:00', '2018-12-14 06:00:00 01:00',
                      '2018-12-14 07:00:00 01:00', '2018-12-14 08:00:00 01:00',
                      '2018-12-14 09:00:00 01:00', '2018-12-14 10:00:00 01:00',
                      '2018-12-14 11:00:00 01:00', '2018-12-14 12:00:00 01:00',
                      '2018-12-14 13:00:00 01:00', '2018-12-14 14:00:00 01:00'])
           
results = pd.DataFrame(index=d)

out = np.where(results.index.hour <= 8, 
               results.index   pd.offsets.DateOffset(hour=8), 
               results.index   pd.offsets.DateOffset(days=1, hour=8))

print (pd.DatetimeIndex(out))
DatetimeIndex(['2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
               '2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00'],
              dtype='datetime64[ns, pytz.FixedOffset(60)]', freq=None)
  

Другая идея — использовать Timedelta s и добавлять день, только если условие True :

 m = results.index.hour > 8
out = results.index   pd.offsets.DateOffset(hour=8)    pd.Timedelta(days=1) * m
print (out)
DatetimeIndex(['2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
               '2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00'],
              dtype='datetime64[ns, pytz.FixedOffset(60)]', freq=None)
  

 m = results.index.hour > 8
out = results.index.floor('d')   pd.Timedelta(hours=8)    pd.Timedelta(days=1) * m
print (out)
DatetimeIndex(['2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
               '2018-12-14 08:00:00 01:00', '2018-12-14 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00',
               '2018-12-15 08:00:00 01:00', '2018-12-15 08:00:00 01:00'],
              dtype='datetime64[ns, pytz.FixedOffset(60)]', freq=None)
  

Комментарии:

1. @MrFuppes — я вижу.

2. Спасибо @jezrael, я не уточнил в своем вопросе, но мне нужна функция (или строка), которую я могу передать методу ceil(). Итак, что-то вроде results.index.dt.ceil(freq=’1D8H’). Или results.index.dt.ceil(freq=custom_function_offset). Я также должен объяснить, что у меня очень длинный скрипт, который использует много вызовов ceil (), потому что до сих пор я в основном использовал общие частоты, такие как ‘H’ и ‘D’.

3. @WhiteHat — Для меня работает print (results.index.ceil(freq='1D8H')) , но, похоже, он возвращает неверный вывод. Я думаю, что это реализовано неправильно.