You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas Dataframe:重叠工时表条目替换与调整的向量化实现问询

问题描述

我正在处理从源系统导出至目标系统的Timesheet数据,源系统数据存在重叠条目,但目标系统不允许该情况。业务规则为:若出现重叠条目,介入事件将替代当前事件,直至介入事件结束后当前事件恢复。

源系统数据(含重叠)

员工班次类型开始时间结束时间
1SHFT-1Sleep19/06/2023 10:00PM20/06/2023 07:00AM
1ACT-1Disturbance19/06/2023 11:00PM19/06/2023 11:30PM
1ACT-2Disturbance20/06/2023 02:00AM20/06/2023 03:00AM
1ACT-3Disturbance20/06/2023 06:30AM20/06/2023 07:00AM

实际场景:员工原计划执行Sleep任务,期间出现3次Disturbance事件,每次干扰结束后回归Sleep任务,仅最后一次因Sleep任务结束无需回归。

目标系统要求格式

员工班次类型开始时间结束时间
1SHFT-1Sleep19/06/2023 10:00PM19/06/2023 11:00PM
1ACT-1Disturbance19/06/2023 11:00PM19/06/2023 11:30PM
1SHFT-1Sleep19/06/2023 11:30PM20/06/2023 02:00AM
1ACT-2Disturbance20/06/2023 02:00AM20/06/2023 03:00AM
1SHFT-1Sleep20/06/2023 03:00AM20/06/2023 06:30AM
1ACT-3Disturbance20/06/2023 06:30AM20/06/2023 07:00AM

需要找到比while not_finished iterate_all not_finished = changes_occured更高效的Pandas向量化实现方案。


基于Pandas的向量化实现方案

核心思路是提取所有关键时间节点(主事件起止、干扰事件起止),排序后生成连续时间区间,再为每个区间匹配对应事件类型,全程用批量操作替代循环迭代。

步骤1:数据预处理

先将时间列转换为datetime类型,方便后续时间计算:

import pandas as pd

# 加载源数据
data = pd.DataFrame({
    '员工': [1, 1, 1, 1],
    '班次': ['SHFT-1', 'ACT-1', 'ACT-2', 'ACT-3'],
    '类型': ['Sleep', 'Disturbance', 'Disturbance', 'Disturbance'],
    '开始时间': ['19/06/2023 10:00PM', '19/06/2023 11:00PM', '20/06/2023 02:00AM', '20/06/2023 06:30AM'],
    '结束时间': ['20/06/2023 07:00AM', '19/06/2023 11:30PM', '20/06/2023 03:00AM', '20/06/2023 07:00AM']
})

# 转换时间格式
data['开始时间'] = pd.to_datetime(data['开始时间'], format='%d/%m/%Y %I:%M%p')
data['结束时间'] = pd.to_datetime(data['结束时间'], format='%d/%m/%Y %I:%M%p')

步骤2:分离主事件与干扰事件

假设主事件为Sleep类型,干扰事件为Disturbance,按员工分组处理(示例为单员工,多员工可外层加groupby('员工')):

# 提取主事件(单员工场景取第一条)
main_event = data[data['类型'] == 'Sleep'].iloc[0]
# 提取干扰事件并按开始时间排序
disturbances = data[data['类型'] == 'Disturbance'].sort_values('开始时间').reset_index(drop=True)

步骤3:生成排序后的关键时间点

收集主事件和所有干扰事件的起止时间,去重后排序:

# 收集所有时间节点
time_points = pd.Series(
    [main_event['开始时间'], main_event['结束时间']] +
    list(disturbances['开始时间']) + list(disturbances['结束时间'])
)
# 去重并按时间排序
time_points = time_points.drop_duplicates().sort_values().reset_index(drop=True)

步骤4:匹配区间与事件类型

遍历时间区间,判断当前区间属于主事件还是干扰事件,生成结果:

# 初始化结果列表
result = []

for idx in range(len(time_points) - 1):
    interval_start = time_points[idx]
    interval_end = time_points[idx+1]
    
    # 检查当前区间是否被干扰事件覆盖
    mask = (disturbances['开始时间'] <= interval_start) & (disturbances['结束时间'] >= interval_end)
    if mask.any():
        # 匹配对应的干扰事件
        dist_row = disturbances[mask].iloc[0]
        result.append({
            '员工': dist_row['员工'],
            '班次': dist_row['班次'],
            '类型': dist_row['类型'],
            '开始时间': interval_start,
            '结束时间': interval_end
        })
    else:
        # 匹配主事件
        result.append({
            '员工': main_event['员工'],
            '班次': main_event['班次'],
            '类型': main_event['类型'],
            '开始时间': interval_start,
            '结束时间': interval_end
        })

# 转换为DataFrame并格式化时间输出
final_df = pd.DataFrame(result)
final_df['开始时间'] = final_df['开始时间'].dt.strftime('%d/%m/%Y %I:%M%p')
final_df['结束时间'] = final_df['结束时间'].dt.strftime('%d/%m/%Y %I:%M%p')

验证结果

运行后final_df将完全匹配目标系统的格式,且所有时间判断、数据匹配均采用Pandas批量操作,避免了循环迭代的低效问题。


内容的提问来源于stack exchange,提问作者Paul O

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 00:23:18