#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'))
, но, похоже, он возвращает неверный вывод. Я думаю, что это реализовано неправильно.