反转数据框中给定日期的时间

时间:2019-04-05 18:18:12

标签: python pandas datetime

对于包含开始时间和结束时间的数据框,我想“反转”给定日期的时间。当然,有一种“强力”方法可以通过遍历数据框并具有很多if条件来做到这一点,但我想知道是否有更优雅的方法,例如回填/正向填充。

将其视为一个数据框,其中工作时间用带有开始和结束时间的行表示,而我最终想要的是该日期的空闲时间。 数据帧以单调递增的开始时间排序,并且在日期更改时已截止,因此时间始于例如2019-04-04 22:00和结束于2019-04-05 04:00由两行表示2019-04-04 22:00至2019-04-05 00:00和2019-04-05 00:00至2019-04-05 04:00。这应该使问题更容易。

示例代码:

import pandas as pd
import datetime

df = pd.DataFrame({'date': [datetime.date(2019, 4, 4), datetime.date(2019, 4, 5), datetime.date(2019, 4, 5)],
                   'start': [pd.Timestamp(2019, 4, 4, 10), pd.Timestamp(2019, 4, 5, 0), pd.Timestamp(2019, 4, 5, 14)],
                   'end': [pd.Timestamp(2019, 4, 4, 16), pd.Timestamp(2019, 4, 5, 4), pd.Timestamp(2019, 4, 5, 18)]})

所以从这里开始:

2019-04-04   2019-04-04 10:00:00   2019-04-04 16:00:00
2019-04-05   2019-04-05 00:00:00   2019-04-05 04:00:00
2019-04-05   2019-04-05 14:00:00   2019-04-05 18:00:00

我希望结果是这样的数据框:

2019-04-04   2019-04-04 00:00:00   2019-04-04 10:00:00
2019-04-04   2019-04-04 16:00:00   2019-04-05 00:00:00
2019-04-05   2019-04-05 04:00:00   2019-04-05 14:00:00
2019-04-05   2019-04-05 18:00:00   2019-04-06 00:00:00

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您可以使用shift来完成此操作。问题出在最后一行,我正在尝试找出如何最好地重建。

编辑:我在最后一行给了我最好的镜头,但最终变得笨拙。对于最后一行的任何反馈,我都很高兴。原则上,使用shift将使超级简单。您显然可以在添加最后一行之前删除startend,我只是在演示如何做到这一点而不会丢失数据。

import pandas as pd
import numpy as np
import datetime as dt

df = pd.DataFrame({'date': [dt.date(2019, 4, 4), dt.date(2019, 4, 5), dt.date(2019, 4, 5)],
                   'start': [pd.Timestamp(2019, 4, 4, 10), pd.Timestamp(2019, 4, 5, 0), pd.Timestamp(2019, 4, 5, 14)],
                   'end': [pd.Timestamp(2019, 4, 4, 16), pd.Timestamp(2019, 4, 5, 4), pd.Timestamp(2019, 4, 5, 18)]})

df = df[['date', 'start', 'end']]

saved_shift_ending = df['end'].iloc[-1]  # we want end of last shift
saved_end_date = df['date'].iloc[-1]     # we also want the date value

start_date = df['date'].min()
end_date = (df['date'].max() + dt.timedelta(days=1))

df['other_start'] = df['end'].shift(1)
df['other_end'] = df['start']

df.loc[0, 'other_start'] = start_date # The first value is NaT after shift

last_row = pd.DataFrame([[saved_end_date.strftime('%Y-%m-%d'), 
                         np.nan, 
                         np.nan, 
                         saved_shift_ending, 
                         end_date]],
                        columns=['date', 'start', 'end', 'other_start',
                                'other_end'])

df = df.append(last_row)

df.drop(['start', 'end'], axis=1, inplace=True)
print(df)

答案 1 :(得分:0)

roganjosh回答了一般情况,但是我不得不查看每日的“空闲时间”,为此,我必须添加一些人工日期边界作为在开始和结束之间具有零时间的行。最后,try { Thread.sleep(3000); } catch (InterruptedException ex) { } 是我所追求的。 我将其打包成一个函数以提高可重用性,如果有人有更优雅的解决方案,请随时分享。

这是我的代码:

.shift()