使用Pandas计算员工班次间有效休息间隔时长
完整解决方案
原代码的核心问题是直接过滤了间隔不足15分钟的记录,且未按员工分组处理,也没覆盖“当日首行设为0”的规则。以下是符合所有要求的完整实现:
步骤1:数据预处理
先确保时间字段为datetime类型,并按员工和班次开始时间排序:
import pandas as pd # 转换时间字段格式 df['start_time'] = pd.to_datetime(df['start_time']) df['end_time'] = pd.to_datetime(df['end_time']) # 按员工ID和班次开始时间排序,保证数据顺序正确 df = df.sort_values(by=['Worker_ID', 'start_time']).reset_index(drop=True)
步骤2:计算班次间隔与有效休息标识
按员工分组,计算两次班次的间隔,同时标记出需要重置为0的有效休息节点:
# 计算当前班次与上一班次的间隔时间(分钟) df['minutes_between_shifts'] = df.groupby('Worker_ID').apply( lambda x: (x['start_time'] - x['end_time'].shift()).dt.total_seconds()/60 ).reset_index(drop=True) # 标记有效休息节点:当日首行 或 班次间隔≥15分钟 df['is_valid_break'] = (df['minutes_between_shifts'] >= 15) | ( df.groupby(['Worker_ID', df['start_time'].dt.date])['start_time'].rank(method='first') == 1 )
步骤3:生成休息分组并计算累计时长
基于有效休息节点生成分组,再在每个分组内累计自上次休息后的时长:
# 按员工生成连续的休息分组ID,每遇到有效休息则分组ID递增 df['break_group'] = df.groupby('Worker_ID')['is_valid_break'].cumsum() # 计算单个班次的时长(分钟) df['shift_duration'] = (df['end_time'] - df['start_time']).dt.total_seconds()/60 # 累计每个休息组内的时长,shift后实现“自上次休息到当前班次开始的时长” df['minutes_since_previous_break'] = df.groupby(['Worker_ID', 'break_group'])['shift_duration'].cumsum().shift(fill_value=0)
步骤4:重置有效休息节点的字段值
对标记为有效休息的记录,将minutes_since_previous_break设为0:
df.loc[df['is_valid_break'], 'minutes_since_previous_break'] = 0
完整代码整合
import pandas as pd def compute_minutes_since_break(df): # 预处理时间字段 df['start_time'] = pd.to_datetime(df['start_time']) df['end_time'] = pd.to_datetime(df['end_time']) # 排序 df = df.sort_values(by=['Worker_ID', 'start_time']).reset_index(drop=True) # 计算班次间隔 df['minutes_between_shifts'] = df.groupby('Worker_ID').apply( lambda x: (x['start_time'] - x['end_time'].shift()).dt.total_seconds()/60 ).reset_index(drop=True) # 标记有效休息节点 df['is_valid_break'] = (df['minutes_between_shifts'] >= 15) | ( df.groupby(['Worker_ID', df['start_time'].dt.date])['start_time'].rank(method='first') == 1 ) # 生成休息分组 df['break_group'] = df.groupby('Worker_ID')['is_valid_break'].cumsum() # 计算班次时长和累计值 df['shift_duration'] = (df['end_time'] - df['start_time']).dt.total_seconds()/60 df['minutes_since_previous_break'] = df.groupby(['Worker_ID', 'break_group'])['shift_duration'].cumsum().shift(fill_value=0) # 重置有效休息后的字段值 df.loc[df['is_valid_break'], 'minutes_since_previous_break'] = 0 # 清理中间字段(可选) df = df.drop(columns=['minutes_between_shifts', 'is_valid_break', 'break_group', 'shift_duration']) return df # 使用示例 # df = pd.read_csv('your_shift_records.csv') # df = compute_minutes_since_break(df)
关键逻辑说明
- 分组隔离:所有计算按
Worker_ID分组,避免不同员工的数据相互干扰 - 当日首行识别:通过
start_time.dt.date结合组内排名,精准定位每个员工当日的第一条班次记录 - 有效休息覆盖:同时处理“间隔≥15分钟”和“当日首行”两种需要重置为0的场景
- 累计时长计算:利用分组累加实现跨班次的时长统计,确保间隔不足15分钟时持续累加时长
内容的提问来源于stack exchange,提问作者datadatadata
相关产品推荐
相关产品推荐

