如何用Python Pandas计算连续或并行任务的实际加工时长?
计算多机床并行/连续加工工件的实际时长
我有一个Pandas DataFrame,每行记录工件在对应机床的加工起止时间。每个工件可能在多台机床上连续或并行加工,需要计算所有工件的实际加工时长。示例数据如下:
| Object | Machine | T start | T end |
|---|---|---|---|
| 1 | A | 17:26 | 17:57 |
| 1 | B | 17:26 | 18:33 |
| 1 | C | 18:56 | 19:46 |
| 2 | A | 14:00 | 15:00 |
| 2 | C | 14:30 | 15:00 |
| 3 | A | 12:00 | 12:30 |
| 3 | C | 13:00 | 13:45 |
正确结果应为:工件1实际时长117分钟,工件2为60分钟,工件3为75分钟。
现有方案的问题
我尝试用groupby计算每个工件的加工时长总和、最早开始时间和最晚结束时间,再通过函数取两者的较小值,但这种方法对工件1计算错误(得到140分钟,正确应为117分钟),仅对工件2、3有效。现有方案的计算结果和代码如下:
| Object | min | max | sumT | LT_ACTUAL |
|---|---|---|---|---|
| 1 | 17:26 | 19:46 | 148 | 140 ERROR! |
| 2 | 14:00 | 15:00 | 90 | 60 OK! |
| 3 | 12:00 | 13:45 | 75 | 75 OK! |
现有代码:
def calc_lead_time(min_t_start, max_t_end, t_sum): t_max_min = (max_t_end - min_t_start) / pd.Timedelta(minutes=1) if t_max_min <= t_sum: return t_max_min else: return t_sum df['LT_ACTUAL'] = df.apply(lambda x : calc_lead_time(x['min'], x['max'], x['sumT']), axis=1)
问题根源
现有方法的逻辑错误在于:当工件的加工时间段存在并行+间隔的情况时,首尾时间差会包含无加工的空白间隔,而总时长是各段加工时间的总和,两者的较小值并不能准确反映实际加工时长。比如工件1,首尾时间差是140分钟(17:26到19:46),但其中18:33到18:56是无加工的间隔,实际有效加工时长是合并重叠/连续区间后的总长度。
正确解决方案
需要对每个工件的所有加工时间段进行区间合并,再计算合并后所有区间的总时长。步骤如下:
- 确保时间列是
datetime类型(若当前为字符串格式) - 按工件分组,对每组的时间段按开始时间排序
- 合并重叠或连续的区间
- 计算合并后各区间的时长总和
代码实现
import pandas as pd # 将时间列转为datetime类型(补充统一日期方便计算) df['T start'] = pd.to_datetime('2024-01-01 ' + df['T start']) df['T end'] = pd.to_datetime('2024-01-01 ' + df['T end']) def calculate_actual_lt(group): # 按开始时间排序时间段 sorted_intervals = group[['T start', 'T end']].sort_values('T start') intervals = sorted_intervals.values.tolist() if not intervals: return 0 # 合并区间 merged = [intervals[0]] for current_start, current_end in intervals[1:]: last_start, last_end = merged[-1] if current_start <= last_end: # 重叠或连续,合并为更大的区间 new_end = max(last_end, current_end) merged[-1] = [last_start, new_end] else: # 无重叠,添加新的独立区间 merged.append([current_start, current_end]) # 计算合并后所有区间的总时长(分钟) total_minutes = sum((end - start).total_seconds() // 60 for start, end in merged) return total_minutes # 按工件分组计算实际加工时长 result = df.groupby('Object').apply(calculate_actual_lt).reset_index(name='LT_ACTUAL') print(result)
输出结果
Object LT_ACTUAL 0 1 117 1 2 60 2 3 75
内容的提问来源于stack exchange,提问作者Alessio
相关产品推荐
相关产品推荐

