如何用Pandas生成存在班次冲突的DataFrame?
找出unfilled_shifts中与filled_shifts冲突的班次
核心思路
要判断未填充班次是否被已填充班次完全包含,首先需要将分散的日期和时间字段合并为可比较的datetime类型,再通过时间范围的包含关系筛选冲突记录。
步骤1:合并日期与时间为Datetime类型
分开的日期和时间无法直接进行范围比较,先将两个DataFrame中的日期和时间字段合并为完整的时间戳:
import pandas as pd # 处理filled_shifts,生成完整的开始/结束时间戳 filled_shifts['start_dt'] = pd.to_datetime(filled_shifts['Start Date'] + ' ' + filled_shifts['Start Time']) filled_shifts['end_dt'] = pd.to_datetime(filled_shifts['End Date'] + ' ' + filled_shifts['End Time']) # 处理unfilled_shifts,生成完整的开始/结束时间戳 unfilled_shifts['start_dt'] = pd.to_datetime(unfilled_shifts['Start Date'] + ' ' + unfilled_shifts['Start Time']) unfilled_shifts['end_dt'] = pd.to_datetime(unfilled_shifts['End Date'] + ' ' + unfilled_shifts['End Time'])
步骤2:筛选冲突班次
提供两种适配不同数据量的方法:
方法一:Merge+条件筛选(适合中小数据量)
先按日期合并两个DataFrame减少无效比较,再筛选符合冲突条件的记录:
# 按班次开始日期合并,缩小比较范围 merged_df = unfilled_shifts.merge(filled_shifts, on='Start Date', suffixes=('_unfilled', '_filled')) # 筛选:未填充班次的开始时间≥已填充班次开始时间,且未填充班次结束时间≤已填充班次结束时间 conflict_records = merged_df[ (merged_df['start_dt_unfilled'] >= merged_df['start_dt_filled']) & (merged_df['end_dt_unfilled'] <= merged_df['end_dt_filled']) ] # 提取对应的未填充冲突班次(去重,避免同一班次被多次匹配) conflicting_unfilled = unfilled_shifts[unfilled_shifts.index.isin(conflict_records.index.get_level_values(0))].drop_duplicates()
方法二:Interval索引优化(适合大数据量)
利用pandas的IntervalIndex实现高效的时间范围包含判断:
# 为已填充班次创建时间间隔索引 filled_intervals = pd.IntervalIndex.from_arrays( filled_shifts['start_dt'], filled_shifts['end_dt'], closed='both' # 包含区间两端的时间点 ) # 为未填充班次创建时间间隔索引 unfilled_intervals = pd.IntervalIndex.from_arrays( unfilled_shifts['start_dt'], unfilled_shifts['end_dt'], closed='both' ) # 直接判断每个未填充班次是否被任意已填充班次包含 conflict_mask = unfilled_intervals.isin(filled_intervals) conflicting_unfilled = unfilled_shifts[conflict_mask]
注意事项
- 如果存在跨天的班次(
End Date与Start Date不同),上述代码依然适用,datetime类型会自动处理日期跨越。 - 方法一中若同一未填充班次匹配多个已填充班次,需用
drop_duplicates()去重,保证结果唯一。 - 方法二的向量化操作效率远高于循环遍历,数据量越大优势越明显。
内容的提问来源于stack exchange,提问作者grungrun
相关产品推荐
相关产品推荐

