如何让groupby每天在给定时间开始计算秒数?

时间:2018-05-25 14:08:55

标签: python-3.x pandas time-series

我有一个带有DateTimeIndex的pandas df,如下所示:

time
2016-06-10 10:09:16        0.0
2016-06-10 13:18:08    11332.0
2016-06-13 09:00:22        0.0
2016-06-13 10:14:12     4430.0
2016-06-13 13:27:14    11582.0
2016-06-13 15:15:59     6525.0
2016-06-13 16:25:25     4166.0
2016-06-14 09:29:23        0.0
2016-06-14 13:12:31    13388.0
2016-06-14 16:25:28    11577.0

该列显示自上次观察/行以来的秒数,并且每天都会重置,如下所示:

def time_calc(df):
    res = df.index.to_series().diff().dt.seconds.fillna(0)
    df = df.join(res)
    return df

df = df.groupby(df.index.date, group_keys=False).apply(time_calc)

但是,我希望每天从09:00:00开始计算秒数,这样我的df应该是这样的:

time
2016-06-10 10:09:16     4156.0
2016-06-10 13:18:08    11332.0
2016-06-13 09:00:22       22.0
2016-06-13 10:14:12     4430.0
2016-06-13 13:27:14    11582.0
2016-06-13 15:15:59     6525.0
2016-06-13 16:25:25     4166.0
2016-06-14 09:29:23     1763.0
2016-06-14 13:12:31    13388.0
2016-06-14 16:25:28    11577.0

关于如何实现这一点的任何指示都将非常感激......

2 个答案:

答案 0 :(得分:2)

我明白你现在想做什么。您可以分两步完成此操作。

首先,计算除第一个值以外的所有内容的时差。这可以通过groupby + shift来完成。第一个值始终设置为NaT,因此您可以将其设置为9:00:00

的时差
import pandas as pd

df = df.reset_index()
df['seconds'] = df.groupby(df.time.dt.date).time.apply(lambda x: x -x.shift(1))
df.loc[df.seconds.isnull(), 'seconds'] = df.loc[df.seconds.isnull(), 'time'] - pd.to_datetime(df.loc[df.seconds.isnull(), 'time'].astype('str').replace('(?<=\s).*', '9:00:00', regex=True))
df['seconds'] = df.seconds.dt.total_seconds()
df = df.set_index('time')

#                     seconds
#time                        
#2016-06-10 10:09:16   4156.0
#2016-06-10 13:18:08  11332.0
#2016-06-13 09:00:22     22.0
#2016-06-13 10:14:12   4430.0
#2016-06-13 13:27:14  11582.0
#2016-06-13 15:15:59   6525.0
#2016-06-13 16:25:25   4166.0
#2016-06-14 09:29:23   1763.0
#2016-06-14 13:12:31  13388.0
#2016-06-14 16:25:28  11577.0

答案 1 :(得分:2)

这可能不是最佳答案,但可行。

您可以使用Time Deltas来查找此内容。假设您的Pandas Dataframe或Series保存为pd.datetimes,您可以使用pd.to_datetime()执行此操作,您可以从日期时间中减去9小时,然后获取该时间点中的所有秒数,然后以86,400为模数这是一天中的秒数。

pd.to_timedelta(df -  dt.timedelta(hours=9)).dt.total_seconds() % 86400

将给出输出:

0     4156.0
1    15488.0
2       22.0
3     4452.0
4    16034.0
5    22559.0
6    26725.0
7     1763.0
8    15151.0
9    26728.0

然后你需要使用列表理解来完成它:

s2 = [x-y if d1==d2 else x for x,y,d1,d2 in zip(df.seconds[1:], df.seconds[:-1], my_days[1:], my_days[:-1])]
s2.insert(0, df.seconds[0])

 4156.0
11332.0
   22.0
 4430.0
11582.0
 6525.0
 4166.0
 1763.0
13388.0
11577.0

如果你希望它们是整数而不是浮点数,你可以使用。pd.DataFrame.assign()将它分配给列(如果它是数据帧)或者如果你正在处理一个系列就创建一个数据帧。如果您希望索引成为列,只需使用df.reset_index()

我的互动会话如下:

import pandas as pd
import datetime as dt     
time = [ "2016-06-10 10:09:16", "2016-06-10 13:18:08", "2016-06-13 09:00:22", "2016-06-13 10:14:12", "2016-06-13 13:27:14", "2016-06-13 15:15:59", "2016-06-13 16:25:25", "2016-06-14 09:29:23", "2016-06-14 13:12:31", "2016-06-14 16:25:28"]
my_time = pd.Series(time)
my_time = pd.to_datetime(my_time)
df = pd.DataFrame({
     'datetime':my_time.values, 
     'seconds':pd.to_timedelta(my_time -  dt.timedelta(hours=9)).dt.total_seconds() % 86400
   })
my_days = df.datetime.dt.day
s2 = [x-y if d1==d2 else x for x,y,d1,d2 in zip(df.seconds[1:], df.seconds[:-1], my_days[1:], my_days[:-1])]
s2.insert(0, df.seconds[0])
df.loc[:, "seconds"] = s2
print(df)
             datetime  seconds
0 2016-06-10 10:09:16   4156.0
1 2016-06-10 13:18:08  11332.0
2 2016-06-13 09:00:22     22.0
3 2016-06-13 10:14:12   4430.0
4 2016-06-13 13:27:14  11582.0
5 2016-06-13 15:15:59   6525.0
6 2016-06-13 16:25:25   4166.0
7 2016-06-14 09:29:23   1763.0
8 2016-06-14 13:12:31  13388.0
9 2016-06-14 16:25:28  11577.0