如何将天花板应用于pandas DateTime

时间:2015-03-21 00:02:33

标签: python python-3.x pandas python-datetime

假设我有一个pandas数据框,其列值为datetime64[ns]

Out[204]: 
0   2015-03-20 00:00:28
1   2015-03-20 00:01:44
2   2015-03-20 00:02:55
3   2015-03-20 00:03:39
4   2015-03-20 00:04:32
5   2015-03-20 00:05:52
6   2015-03-20 00:06:36
7   2015-03-20 00:07:44
8   2015-03-20 00:08:56
9   2015-03-20 00:09:47
Name: DateTime, dtype: datetime64[ns]

有没有简单的方法将它们转换成最后一分钟后的时间?即我想要以下内容:

Out[204]: 
0   2015-03-20 00:01:00
1   2015-03-20 00:02:00
2   2015-03-20 00:03:00
3   2015-03-20 00:04:00
4   2015-03-20 00:05:00
5   2015-03-20 00:06:00
6   2015-03-20 00:07:00
7   2015-03-20 00:08:00
8   2015-03-20 00:09:00
9   2015-03-20 00:10:00
Name: DateTime, dtype: datetime64[ns]

我编写了一个复杂的代码,首先将它们转换为字符串,然后提取00:09:47的三个部分,将它们转换为整数,然后除非最后一部分(秒)已经00,我制作最后一部分(秒)为00,将1添加到中间部分(分钟),除非中间部分(分钟)已经59,在这种情况下它会添加到第一部分部分(小时)。然后将新整数重新组合回字符串,然后重新构造DateTime

但我在想,可能已经存在一个现有的更简单的解决方案。有人会有什么建议吗?

*编辑*

@Jeff,@ unutbu,谢谢你的回答。我只能在SO中选择一个答案,但两者都有效。

4 个答案:

答案 0 :(得分:5)

这是另一种方式。减去差分秒数(有点像圆形)。这是矢量化的。

In [46]: df.date+pd.to_timedelta(-df.date.dt.second % 60,unit='s')
Out[46]: 
0   2015-03-20 00:01:00
1   2015-03-20 00:02:00
2   2015-03-20 00:03:00
3   2015-03-20 00:04:00
4   2015-03-20 00:05:00
5   2015-03-20 00:06:00
6   2015-03-20 00:07:00
7   2015-03-20 00:08:00
8   2015-03-20 00:09:00
9   2015-03-20 00:10:00
dtype: datetime64[ns

这是另一种方式。将某些内容更改为另一个频率的周期会使其更圆。 (请注意,这是一个有点笨重的ATM,因为期间不是完整的列类型)。这是矢量化的。

In [48]: pd.Series(pd.PeriodIndex(df.date.dt.to_period('T')+1).to_timestamp())
Out[48]: 
0   2015-03-20 00:01:00
1   2015-03-20 00:02:00
2   2015-03-20 00:03:00
3   2015-03-20 00:04:00
4   2015-03-20 00:05:00
5   2015-03-20 00:06:00
6   2015-03-20 00:07:00
7   2015-03-20 00:08:00
8   2015-03-20 00:09:00
9   2015-03-20 00:10:00
dtype: datetime64[ns]

最后一种方法将始终围绕' up'因为我们正在增加地板时期。

答案 1 :(得分:3)

给定一个带有dtype datetime64[ns]列的DataFrame,你可以 使用

df['date'] += np.array(-df['date'].dt.second % 60, dtype='<m8[s]')

添加适当的秒数以获得上限。


例如,

import io
import sys
import numpy as np
import pandas as pd
StringIO = io.BytesIO if sys.version < '3' else io.StringIO

df = '''\
2015-03-20 00:00:00
2015-03-20 00:00:28
2015-03-20 00:01:44
2015-03-20 00:02:55
2015-03-20 00:03:39
2015-03-20 00:04:32
2015-03-20 00:05:52
2015-03-20 00:06:36
2015-03-20 00:07:44
2015-03-20 00:08:56
2015-03-20 00:09:47'''

df = pd.read_table(StringIO(df), sep='\s{2,}', 
                   header=None, parse_dates=[0], names=['date'])

df['date'] += np.array(-df['date'].dt.second % 60, dtype='<m8[s]')
print(df)

产量

                  date
0  2015-03-20 00:00:00
1  2015-03-20 00:01:00
2  2015-03-20 00:02:00
3  2015-03-20 00:03:00
4  2015-03-20 00:04:00
5  2015-03-20 00:05:00
6  2015-03-20 00:06:00
7  2015-03-20 00:07:00
8  2015-03-20 00:08:00
9  2015-03-20 00:09:00
10 2015-03-20 00:10:00

答案 2 :(得分:2)

现在pandas中有一个内置方法Series.dt.ceil()。对于一系列日期时间,可以使用In[92]: t Out[92]: 0 2015-03-20 00:00:28 1 2015-03-20 00:01:44 2 2015-03-20 00:02:55 3 2015-03-20 00:03:39 4 2015-03-20 00:04:32 5 2015-03-20 00:05:52 6 2015-03-20 00:06:36 7 2015-03-20 00:07:44 8 2015-03-20 00:08:56 9 2015-03-20 00:09:47 dtype: datetime64[ns] In[93]: t.dt.ceil('min') Out[93]: 0 2015-03-20 00:01:00 1 2015-03-20 00:02:00 2 2015-03-20 00:03:00 3 2015-03-20 00:04:00 4 2015-03-20 00:05:00 5 2015-03-20 00:06:00 6 2015-03-20 00:07:00 7 2015-03-20 00:08:00 8 2015-03-20 00:09:00 9 2015-03-20 00:10:00 dtype: datetime64[ns]

访问它
ceil()

{{1}}接受频率参数。列出了here的字符串别名。

答案 3 :(得分:1)

我认为这可能需要一些工作,但我认为这大致是你所追求的(我确定有使用.snap或偏移的方式.rollforward,但似乎无法让这些工作):

ps = pd.Series([
        datetime(2015, 1, 1, 19, 18, 34), # roll up min, reset sec
        datetime(2015, 1, 1, 1, 1, 1), # roll up min, reset sec
        datetime(2015, 1, 1, 0, 0, 0), # do nothing
        datetime(2015, 1, 1, 23, 59, 1), # roll day/hr/min, reset sec
        datetime(2015, 1, 31, 23, 59, 1), # roll mth/day/hr/min, reset sec
        datetime(2015, 12, 31, 23, 59, 1) # roll yr/month/day/hr/min - reset sec
    ])
ps[ps.dt.second != 0] = ps.apply(lambda L: (L + timedelta(minutes=1)).replace(second=0))

这给了你:

0   2015-01-01 19:19:00
1   2015-01-01 01:02:00
2   2015-01-01 00:00:00
3   2015-01-02 00:00:00
4   2015-02-01 00:00:00
5   2016-01-01 00:00:00