Как объединить Pandas `DatetimeIndex`?
У меня есть pandas.DatetimeIndex
, например:
pd.date_range('2012-1-1 02:03:04.000',periods=3,freq='1ms')
>>> [2012-01-01 02:03:04, ..., 2012-01-01 02:03:04.002000]
Я хотел бы округлить даты (Timestamp
s) до ближайшей секунды. Как мне это сделать? Ожидаемый результат аналогичен:
[2012-01-01 02:03:04.000000, ..., 2012-01-01 02:03:04.000000]
Можно ли выполнить это, округляя Numpy datetime64[ns]
до секунд, не меняя dtype
[ns]
?
np.array(['2012-01-02 00:00:00.001'],dtype='datetime64[ns]')
Ответы
Ответ 1
Обновление: если вы делаете это в столбце DatetimeIndex/datetime64, лучше использовать np.round
напрямую, а не через apply/map:
np.round(dtindex_or_datetime_col.astype(np.int64), -9).astype('datetime64[ns]')
Старый ответ (с некоторым дополнительным объяснением):
В то время как ответ @Matti - это, безусловно, правильный способ справиться с вашей ситуацией, я думал, что добавлю ответ, как вы можете округлить отметку времени до ближайшей секунды:
from pandas.lib import Timestamp
t1 = Timestamp('2012-1-1 00:00:00')
t2 = Timestamp('2012-1-1 00:00:00.000333')
In [4]: t1
Out[4]: <Timestamp: 2012-01-01 00:00:00>
In [5]: t2
Out[5]: <Timestamp: 2012-01-01 00:00:00.000333>
In [6]: t2.microsecond
Out[6]: 333
In [7]: t1.value
Out[7]: 1325376000000000000L
In [8]: t2.value
Out[8]: 1325376000000333000L
# Alternatively: t2.value - t2.value % 1000000000
In [9]: long(round(t2.value, -9)) # round milli-, micro- and nano-seconds
Out[9]: 1325376000000000000L
In [10]: Timestamp(long(round(t2.value, -9)))
Out[10]: <Timestamp: 2012-01-01 00:00:00>
Следовательно, вы можете применить это ко всему индексу:
def to_the_second(ts):
return Timestamp(long(round(ts.value, -9)))
dtindex.map(to_the_second)
Ответ 2
round()
был добавлен для DatetimeIndex, Timestamp, TimedeltaIndex и Timedelta в pandas 0.18.0. Теперь мы можем сделать следующее:
In[114]: index = pd.DatetimeIndex([pd.Timestamp('2012-01-01 02:03:04.000'), pd.Timestamp('2012-01-01 02:03:04.002'), pd.Timestamp('20130712 02:03:04.500'), pd.Timestamp('2012-01-01 02:03:04.501')])
In[115]: index.values
Out[115]:
array(['2012-01-01T02:03:04.000000000', '2012-01-01T02:03:04.002000000',
'2013-07-12T02:03:04.500000000', '2012-01-01T02:03:04.501000000'], dtype='datetime64[ns]')
In[116]: index.round('S')
Out[116]:
DatetimeIndex(['2012-01-01 02:03:04', '2012-01-01 02:03:04',
'2013-07-12 02:03:04', '2012-01-01 02:03:05'],
dtype='datetime64[ns]', freq=None)
round()
принимает частотный параметр. Строковые псевдонимы для него перечислены здесь.
Ответ 3
Мало смысла в изменении самого индекса - поскольку вы можете просто генерировать с помощью date_range
с нужным параметром частоты, как в вашем вопросе.
Я предполагаю, что вы пытаетесь изменить частоту временных рядов, содержащих данные, и в этом случае вы можете использовать resample
(документация). Например, если у вас есть следующие временные ряды:
dt_index = pd.date_range('2012-1-1 00:00.001',periods=3, freq='1ms')
ts = pd.Series(randn(3), index=dt_index)
2012-01-01 00:00:00 0.594618
2012-01-01 00:00:00.001000 0.874552
2012-01-01 00:00:00.002000 -0.700076
Freq: L
Затем вы можете изменить частоту в секундах, используя resample, указав, как вы хотите агрегировать значения (среднее значение, сумма и т.д.):
ts.resample('S', how='sum')
2012-01-01 00:00:00 0.594618
2012-01-01 00:00:01 0.174475
Freq: S
Ответ 4
Для более общего округления вы можете использовать тот факт, что Pandas Timestamp
объекты в основном используют стандартную библиотеку datetime.datetime
API, включая datetime.datetime.replace()
.
Итак, чтобы решить проблему микросекундного округления, вы можете:
import datetime
import pandas as pd
times = pd.date_range('2012-1-1 02:03:04.499',periods=3,freq='1ms')
# Add 5e5 microseconds and truncate to simulate rounding
times_rounded = [(x + datetime.timedelta(microseconds=5e5)).replace(microsecond=0) for x in times]
from IPython.display import display
print('Before:')
display(list(times))
print('After:')
display(list(times_rounded))
Вывод:
Before:
[Timestamp('2012-01-01 02:03:04.499000', offset='L'),
Timestamp('2012-01-01 02:03:04.500000', offset='L'),
Timestamp('2012-01-01 02:03:04.501000', offset='L')]
After:
[Timestamp('2012-01-01 02:03:04', offset='L'),
Timestamp('2012-01-01 02:03:05', offset='L'),
Timestamp('2012-01-01 02:03:05', offset='L')]
Вы можете использовать ту же технику, например, округлить до ближайшего дня (пока вас не интересуют секунды прыжка и т.п.):
times = pd.date_range('2012-1-1 08:00:00', periods=3, freq='4H')
times_rounded = [(x + datetime.timedelta(hours=12)).replace(hour=0, second=0, microsecond=0) for x in times]
Вдохновленный этим сообщением SO: fooobar.com/info/406108/...