如何舍入 Pandas `DatetimeIndex`?
Posted
技术标签:
【中文标题】如何舍入 Pandas `DatetimeIndex`?【英文标题】:How to round a Pandas `DatetimeIndex`? 【发布时间】:2012-11-26 23:31:01 【问题描述】:我有一个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]')
【问题讨论】:
@hayden,看我的编辑。我只想四舍五入到最接近的秒数。date_range
默认为日频率,我假设您的意思是 pd.date_range('2012-1-1 00:00.000',periods=2, freq='S')
@MattiJohn,请参阅我的更正。我的意思是 same 秒重复。
很好的解决方案here
【参考方案1】:
pandas 0.18.0 中为 DatetimeIndex、Timestamp、TimedeltaIndex 和 Timedelta 添加了round()
方法。现在我们可以执行以下操作:
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()
接受频率参数。它的字符串别名列在here。
【讨论】:
【参考方案2】:对于更一般的舍入,您可以利用 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 帖子的启发:https://***.com/a/19718411/1410871
【讨论】:
【参考方案3】:更新:如果您对 DatetimeIndex / datetime64 列执行此操作,更好的方法是直接使用 np.round
而不是通过应用/映射:
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)
【讨论】:
看来1000000
应该换成1000000000
。
重要的是,我想在 DatetimeIndex
上做。
@user1579844 你当然是对的!我忘了毫秒...哎呀!我已更正此问题并添加了如何将其应用于整个 dt_index。
"Alternatively: t2.value - t2.value % 1000000000" 我相信这会将 t2 向下舍入,而不是最接近的。【参考方案4】:
更改索引本身没有什么意义 - 因为您可以使用date_range
生成问题中所需的频率参数。
我假设您要做的是更改包含数据的时间序列的频率,在这种情况下,您可以使用resample
(documentation)。例如,如果您有以下时间序列:
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
然后您可以使用重新采样将频率更改为秒,指定您希望如何聚合值(平均值、总和等):
ts.resample('S', how='sum')
2012-01-01 00:00:00 0.594618
2012-01-01 00:00:01 0.174475
Freq: S
【讨论】:
这消除了一些行。我只想通过四舍五入到最接近的秒来更改索引值。 啊,抱歉,我没有意识到你想要重复的值。看起来@hayden 的更新答案会做你想做的事以上是关于如何舍入 Pandas `DatetimeIndex`?的主要内容,如果未能解决你的问题,请参考以下文章
如何在包含浮点数和 Nan 或 None 值的同一列中舍入浮点值?