Pandas如何高效实现类似Excel的累加逻辑求解项目最终活动结束日期
方案性能评估及优化方法
原方案性能问题
你现在用的逐行循环方案不是最高效的实现方式,核心问题在于:
- Pandas的
loc逐行赋值属于标量操作,每一次赋值都有额外的索引匹配开销,当数据量超过千行时性能会出现明显下降 - 每次循环都重复计算
np.ceil和pd.to_timedelta,存在大量冗余计算 - 若活动存在多个前驱依赖,原循环会出现赋值覆盖问题,无法正确取所有前驱的最晚结束时间作为当前活动的开始时间,计算结果会出错
性能更优的实现方案
优化核心思路是用Pandas原生的矢量操作替代逐行循环,按拓扑顺序处理活动依赖,一次性完成全量数据计算,具体实现步骤如下:
步骤1:统一预处理时长数据
先把所有活动的时长一次性向上取整并转为timedelta格式,避免循环内重复计算:
import pandas as pd import numpy as np # 提取所有活动时长列 duration_cols = [col for col in df.columns if col.startswith("Duration Act.")] # 整列批量处理为天级timedelta df[duration_cols] = df[duration_cols].apply(np.ceil).apply(pd.to_timedelta, unit="D")
步骤2:生成活动拓扑排序
基于依赖字典生成活动的拓扑序,保证所有前驱活动的处理顺序早于后继活动,避免依赖缺失:
from collections import deque def topological_sort(path): # 构建入度表 in_degree = {} all_nodes = set() for pre, posts in path.items(): all_nodes.add(pre) for post in posts: all_nodes.add(post) in_degree[post] = in_degree.get(post, 0) + 1 for node in all_nodes: if node not in in_degree: in_degree[node] = 0 # 拓扑排序 q = deque([node for node in in_degree if in_degree[node] == 0]) topo_order = [] while q: u = q.popleft() topo_order.append(u) for v in path.get(u, []): in_degree[v] -= 1 if in_degree[v] == 0: q.append(v) return topo_order topo_order = topological_sort(path)
步骤3:按拓扑序批量计算活动时间
直接对整列做矢量计算,多前驱的活动取所有前驱结束时间的最大值作为开始时间:
# 先算起始活动的结束时间 start_act = topo_order[0] df[f"End Date {start_act}"] = df[f"Start Date {start_act}"] + df[f"Duration {start_act}"] # 按拓扑序处理后续活动 for act in topo_order[1:]: # 收集当前活动的所有前驱 pres = [pre for pre, posts in path.items() if act in posts] # 取所有前驱的最晚结束时间作为当前活动开始时间 df[f"Start Date {act}"] = df[[f"End Date {pre}" for pre in pres]].max(axis=1) # 计算当前活动结束时间 df[f"End Date {act}"] = df[f"Start Date {act}"] + df[f"Duration {act}"]
极限优化(不需要中间过程时使用)
如果你只需要最终的项目结束时间,不需要存储所有中间活动的开始/结束日期,可以先预计算每个项目的关键路径(最长依赖路径)总时长,直接加上首个活动的开始时间即可,计算速度最快。
性能对比
假设你有10万行项目数据,原逐行方案的耗时通常在分钟级,优化后的矢量操作方案耗时可以控制在秒级,性能提升可达100倍以上。
内容的提问来源于stack exchange,提问作者Bricam
相关产品推荐
相关产品推荐

