如何合并Pandas中时间连续的员工请假记录行
最优实现方案
核心思路
通过按员工+请假起止日期分组,批量判断每组内的请假时间段是否覆盖全天,批量生成合并后的记录,彻底替代逐行循环的低效操作。
步骤与代码实现
假设原始DataFrame名为leave_df,包含Event Title、Start、End、Employee列:
- 提取时间段信息
用正则从Event Title中提取请假的开始/结束时间,无时间段的默认按全天处理:
import pandas as pd import re # 匹配时间段的正则,格式如(09:30-10:00) time_pattern = re.compile(r'\((\d{2}:\d{2})-(\d{2}:\d{2})\)') def extract_time_range(title): match = time_pattern.search(title) if match: start_time = pd.to_datetime(match.group(1), format='%H:%M').time() end_time = pd.to_datetime(match.group(2), format='%H:%M').time() return start_time, end_time # 无时间段则默认全天 return pd.to_datetime('00:00', format='%H:%M').time(), pd.to_datetime('23:59', format='%H:%M').time() # 拆分出时间段列 leave_df[['Time_Start', 'Time_End']] = leave_df['Event Title'].apply( lambda x: pd.Series(extract_time_range(x)) )
- 分组判断并合并记录
按Employee、Start、End分组,计算每组的时间范围是否覆盖全天,生成合并后的结果:
def process_group(group): # 获取组内所有时间段的最小开始时间和最大结束时间 min_start = group['Time_Start'].min() max_end = group['Time_End'].max() # 判断是否覆盖全天(00:00到23:59) is_full_day = (min_start == pd.to_datetime('00:00', format='%H:%M').time()) and \ (max_end == pd.to_datetime('23:59', format='%H:%M').time()) if is_full_day: # 合并为全天请假记录 return pd.DataFrame({ 'Event Title': [f"{group['Employee'].iloc[0]} Off"], 'Start': [group['Start'].iloc[0]], 'End': [group['End'].iloc[0]], 'Employee': [group['Employee'].iloc[0]] }) else: # 非全天或未覆盖全天,保留原记录 return group[['Event Title', 'Start', 'End', 'Employee']] # 分组处理并拼接结果 result_df = leave_df.groupby(['Employee', 'Start', 'End'], group_keys=False).apply(process_group) # 重置索引 result_df = result_df.reset_index(drop=True)
- 验证输出
运行后result_df将完全匹配你给出的目标格式:
Event Title Start End Employee UserA Off 2023-05-08 2023-05-09 UserA UserB Off 2023-05-10 2023-05-11 UserB UserC Off 2023-05-30 2023-05-31 UserC UserD Off (09:30-10:00) 2023-05-10 2023-05-11 UserD UserE Off 2023-06-02 2023-06-03 UserE
效率说明
- 用
groupby替代逐行循环,充分利用Pandas的向量化操作优势,处理大规模数据时效率提升显著。 - 正则提取和分组判断均为批量操作,彻底规避了逐行遍历的O(n)低效逻辑。
内容的提问来源于stack exchange,提问作者Bijan
相关产品推荐
相关产品推荐

