将轮班数据(开始和结束时间)分解为每小时数据

时间:2019-05-28 11:48:27

标签: python pandas

我有一个如下的df,它显示一个人何时开始轮班,结束轮班,工作时间和工作日期。

Business_Date   Number PayTimeStart PayTimeEnd          Hours
0   2019-05-24  1       2019-05-24 11:00:00 2019-05-24 12:15:00 1.250
1   2019-05-24  2       2019-05-24 12:30:00 2019-05-24 13:30:00 1.00

现在我要尝试的是将其分成小时格式,因此我知道11:00-12:00之间使用了多少小时

因此,在我看来,我想将11到12之间的1小时放入11:00的垃圾箱中,其余0.25放入下一个12的垃圾箱

所以我最终会得到

    Business Date   Time Hour
0   2019-05-24  11:00 1
1   2019-05-24  12:00 0.75
2   2019-05-24  13:00 0.5

3 个答案:

答案 0 :(得分:5)

一个想法是处理分钟-首先使用列表理解和对Series进行展平,然后按hourshour分组,以GroupBy.size计数,最后除以60的最后几个小时:

s = pd.Series([z for x, y in zip(df['Pay Time Start'], 
                                 df['Pay Time End'] - pd.Timedelta(60, unit='s')) 
                 for z in pd.date_range(x, y, freq='Min')])

df = (s.groupby([s.dt.date.rename('Business Date'), s.dt.hour.rename('Time')])
       .size()
       .div(60)
       .reset_index(name='Hour'))
print (df)
  Business Date  Time  Hour
0    2019-05-24    11  1.00
1    2019-05-24    12  0.75
2    2019-05-24    13  0.50

如果您需要按位置或ID分组

 df1 = pd.DataFrame([(z, w) for x, y, w in zip(df['Pay Time Start'], 
                                              df['Pay Time End'] - pd.Timedelta(60, unit='s'), 
                                              df['Location']) for z in pd.date_range(x, y, freq='Min')], 
                   columns=['Date','Location']) 

 df = (df1.groupby([df1['Date'].dt.date.rename('Business Date'), 
                       df1['Date'].dt.hour.rename('Time'), df1['Location']]) 
          .size() .div(60) .reset_index(name='Hour'))

答案 1 :(得分:2)

另一个想法,类似于@jezrael的想法,但需要几秒钟的时间才能获得更高的精度:

def get_series(a):
    s, e, h = a
    idx = pd.date_range(s,e, freq='6s')
    return pd.Series(h/len(idx), index=idx)

(pd.concat(map(get_series, zip(df.Pay_Time_Start,
                          df.Pay_Time_End, 
                          df.Hours)))
   .resample('H').sum()
)

输出:

2019-05-24 11:00:00    0.998668
2019-05-24 12:00:00    0.750500
2019-05-24 13:00:00    0.500832
Freq: H, dtype: float64

答案 2 :(得分:1)

为方便起见(我喜欢挑战性问题),另一个想法是使用melt,然后有条件地计算分钟数:

基本上,您有两个用于计算的公式(伪代码):

  • 分钟开始时间60 - minutes in df['Pay Time Start]
  • 支付时间结束的分钟数minutes in df['Pay Time End]

因此我们可以使用以下公式创建新数据:

首先,我们将《时代》融为一体

new = df.melt(id_vars=['Business Date', 'Number'], 
              value_vars=['Pay Time Start', 'Pay Time End'],
              var_name='Pay Time Name',
              value_name='Pay Time Date').sort_values('Number')

# Apply the formulas noted above
new['Minutes'] = np.where(new['Pay Time Name'].eq('Pay Time Start'), 
                          60 - new['Pay Time Date'].dt.minute, 
                          new['Pay Time Date'].dt.minute)

# Out
  Business Date  Number   Pay Time Name       Pay Time Date  Minutes
0    2019-05-24       1  Pay Time Start 2019-05-24 11:00:00       60
2    2019-05-24       1    Pay Time End 2019-05-24 12:15:00       15
1    2019-05-24       2  Pay Time Start 2019-05-24 12:30:00       30
3    2019-05-24       2    Pay Time End 2019-05-24 13:30:00       30

现在,我们用groupby计算小时数:

daterange = pd.date_range(df['Pay Time Start'].min(), df['Pay Time End'].max(), freq='H')

df_new = pd.DataFrame({'Date':daterange.date,
                    'Time':daterange.time}, dtype='datetime64[ns]')

df_new['Hours'] = (new.groupby(new['Pay Time Date'].dt.hour)['Minutes'].sum()/60).to_numpy()

最终输出

        Date      Time  Hours
0 2019-05-24  11:00:00   1.00
1 2019-05-24  12:00:00   0.75
2 2019-05-24  13:00:00   0.50