【问题标题】:compare a datetime column only to time in pandas仅将 datetime 列与 pandas 中的时间进行比较
【发布时间】:2017-08-08 06:51:56
【问题描述】:

我有一个像下面这样的df

col1, mydate
1, 25-DEC-2016 09:15:00
2, 25-DEC-2016 10:14:00
3, 25-DEC-2016 10:16:00
4, 25-DEC-2016 10:18:56
2, 25-DEC-2016 11:14:00
2, 25-DEC-2016 10:16:00

df.info(): mydate    323809 non-null object

我需要根据时间来这个数据框,比如df的时间小于10:15:00,df的时间小于11:15:00

所以使用

创建了我的切片间隔
times=[pd.to_datetime(i) for i in '10:15:00','11:15:00','12:15:00','13:15:00','14:15:00','15:15:00', '15:30:00']

然后我将 mydate 类型转换为时间 这需要很多时间

df['mydate']=df4.mydate.apply(lambda x: pd.to_datetime(x,infer_datetime_format=True).time())

上述命令我认为可以优化,或者应该有更好/更快的方式。

那我就干吧

for time in times:
  slice = df[df.mydate<time.time()]

我的意图只是将 df.mydate 时间与 ['10:15:00','11:15:00','12:15:00','13:15:00','14:15:00','15:15:00', '15:30:00'] (但不是日期) 进行比较,并简单地将 df 子集

上述方法对我来说很好,但我正在寻找更好的方法。

补充: 有趣的是,使用

对 mydate 进行排序非常快(即使我没有将 mydate col 转换为 datetime)
df.sort_values(by='mydate')

这让我认为我的子集化方式应该更快。

mydate col 将始终为 25-DEC-2016 09:15:00 格式(注意 DEC 不是 Dec)我可以使用 format='%d-%b-%Y %H:%M:%S'

【问题讨论】:

  • 为什么不直接使用 lambda 函数来获取时间子字符串,然后只使用字符串比较就可以了。我认为时间转换会花费时间。减少转化时间会很有帮助。

标签: python pandas datetime


【解决方案1】:

首先,我建议在整个数组/系列上使用pd.to_datetime,所以它是:

pd.to_datetime(['10:15:00','11:15:00','12:15:00','13:15:00']).time

而不是

[pd.to_datetime(i).time() for i in ['10:15:00','11:15:00','12:15:00','13:15:00']]

其次,您对格式的看法是正确的。正如pd.to_datetime 的文档中所述,使用起来要快得多(x5-10 倍)

pd.to_datetime(['25-DEC-2016 09:15:00', '25-DEC-2016 09:15:00'],
               format='%d-%b-%Y %H:%M:%S')

而不是

pd.to_datetime(['25-DEC-2016 09:15:00', '26-DEC-2016 09:15:00'], 
               infer_datetime_format=True)

现在考虑您的数据框:

df = pd.DataFrame({'col1': [1, 2, 3, 2], 
                   'mydate': ['25-DEC-2016 09:15:00',
                              '25-DEC-2016 11:15:00', 
                              '26-DEC-2016 11:15:00', 
                              '26-DEC-2016 12:15:00']})
>>>
   col1                mydate
0     1  25-DEC-2016 09:15:00
1     2  25-DEC-2016 11:15:00
2     3  26-DEC-2016 11:15:00
3     2  26-DEC-2016 12:15:00

您可以先将mydate 列转换为实际的datetime 系列:

df['mydate'] = pd.to_datetime(df.mydate, format='%d-%b-%Y %H:%M:%S')

然后您将能够通过dt 访问器访问datetime 字段(以及更多):

df.mydate.dt.date
>>>
0    2016-12-25
1    2016-12-25
2    2016-12-26
3    2016-12-26

df.mydate.dt.time
>>>
0    09:15:00
1    11:15:00
2    11:15:00
3    12:15:00

所以在计算切片时可以使用:

for time in times:
    slice = df[df.mydate.dt.time < time]
    print(time, slice, sep='\n')
>>>
10:15:00
   col1              mydate
0     1 2016-12-25 09:15:00
11:15:00
   col1              mydate
0     1 2016-12-25 09:15:00
12:15:00
   col1              mydate
0     1 2016-12-25 09:15:00
1     2 2016-12-25 11:15:00
2     3 2016-12-26 11:15:00
13:15:00
   col1              mydate
0     1 2016-12-25 09:15:00
1     2 2016-12-25 11:15:00
2     3 2016-12-26 11:15:00
3     2 2016-12-26 12:15:00

注意你得到的实际上不是切片,因为它们有重叠的记录,所以你可能想使用类似的东西:

for start, end in zip(times, times[1:]):
    slice = df[(start <= df.mydate.dt.time) & (df.mydate.dt.time <= end)]

最后一点,您可以使用来自 pandas 的 group by 操作来获得您尝试使用 for 循环完成的任务。您只需要准备一个mytime 列,仅包含时间:

df['mytime'] = df.mydate.dt.time
groups = df.groupby('mytime')

for group_key, group_df in groups:
    print(group_key, group_df, sep='\n')
>>>
09:15:00
   col1              mydate    mytime
0     1 2016-12-25 09:15:00  09:15:00
11:15:00
   col1              mydate    mytime
1     2 2016-12-25 11:15:00  11:15:00
2     3 2016-12-26 11:15:00  11:15:00
12:15:00
   col1              mydate    mytime
3     2 2016-12-26 12:15:00  12:15:00

好处是您不需要对单个数据帧进行操作,但您可以同时对每个组应用相同的操作和聚合:

groups.size()
>>>
mytime
09:15:00    1
11:15:00    2
12:15:00    1

groups.sum()
>>>
          col1
mytime        
09:15:00     1
11:15:00     5
12:15:00     2

【讨论】:

    【解决方案2】:

    我相信 timedelta 更适合在 pandas 中工作 - 所以首先 split 字符串列并选择转换时间:

    df['mydate'] = pd.to_timedelta(df['mydate'].str.split().str[1])
    print (df)
       col1   mydate
    0     1 09:15:00
    1     2 10:14:00
    2     3 10:16:00
    3     4 10:18:56
    4     2 11:14:00
    5     2 10:16:00
    

    也转换list

    times=pd.to_timedelta(['10:15:00','11:15:00','12:15:00',
                           '13:15:00','14:15:00','15:15:00', '15:30:00'])
    print (times)
    TimedeltaIndex(['10:15:00', '11:15:00', '12:15:00', '13:15:00', '14:15:00',
                    '15:15:00', '15:30:00'],
                   dtype='timedelta64[ns]', freq=None)
    

    最后创建切片:

    for time in times:
      sl = df[df.mydate<time]
      print (sl)
    

    【讨论】:

    • 谢谢。作为另一个疑问,我想知道df.sort_values(by='mydate') 如何对值进行排序(没有任何类型转换)。这样排序是不是一个好方法?
    猜你喜欢
    • 2016-08-06
    • 2020-05-20
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    • 2020-05-30
    • 2021-06-13
    • 2021-12-26
    • 2018-06-14
    相关资源
    最近更新 更多