网络计划技术——关键路线法(Python)
关键路径法是基于进度网络模型的方法,用网络图表示各项活动之间的相互关系,获得在一定工期、成本、资源约束条件下的最优进度安排。关键路径法源于美国杜邦公司对于项目管理控制成本、减少工期的研究。1959年,Kelly 和 Walker 在论文 Critical Path Planning and Scheduling 中提出了关键路径法的基本原理和方法,将该方法应用到杜邦新工厂的建设,使该工程提前两个月完工。杜邦公司采用此法安排施工和维修等计划,每年节约资金100多万美金,取得了良好的经济效益,现今是项目管理技术的核心方法。
一、关键路径法
一个大型工程或项目包括很多活动,关键路径是项目中时间最长的活动顺序,决定着可能的项目最短工期。关键路径法将项目分解成为多个独立的活动并确定每个活动的工期,然后用逻辑关系(结束-开始、结束-结束、开始-开始和开始-结束)将活动连接。首先使用正推法(Forward pass),从起点开始向后计算,依次计算每个顶点(事件)的最早开始时间 ES;然后再使用逆推法(Backward pass),从终点开始向前计算,依次计算每个顶点(事件)的最迟结束时间 LF。进而可以求出每条边(工序)的最早结束时间 EF 和最迟开始时间 LS。最早开始时间 ES 和最迟开始时间 LS 相等的边,就是关键路径上的边,对应的工序是关键工序。
1.1 作业明细表
作业(或工序)明细表是管理活动与网络技术应用的接口,其给出各工序间的前后逻辑关系的以及资源的使用情况,它是管理实践经验的结晶。网络计划图一般用在复杂的项目管理中,绘制网络计划图必须好下列准备工作。
(1)确定计划目标
网络计划的目标是多个方面和综合的目标,正是这个特点决定了网络计划的复杂性。一般按照不同的要求可以分成三类:一是时间要求;一是资源要求;一是费用要求。
(2)项目任务活动的分解
将整个项目根据技术上的需要分解为若干个互相独立的可执行的活动,通常把这种互相独立的活动称为工序或作业
(3)确定各工序的衔接顺序
明确各项工序之间的先后逻辑关系。工序之间存在执行的先后顺序关系,如需先完成A工序才能进行B工序,则称A为B紧前工序,B为A紧后工序,列出工序明细,以便建立整个项目的网络图以表示各项工序之间的相互关系。
(4)确定各个工序时间
确定各项工序所需的时间、人力、物力。一般将完成工序所需要的时间,称为工时。
后面三项准备工作一般以工序明细表或作业明细表的形式给出,所有的网络计划分析都在这个前提下执行。
1.2 工序时间参数的计算
ES:最早开始时间(Earliest Start),指某项活动能够开始的最早时间,取决于该项活动的所有紧前工作的结束时间,由顺推法计算 ES = max{EF(preceding activities)}。
EF:最早结束时间(Earliest Finish),指某项活动能够完成的最早时间。EF = ES+DU, DU为该活动的持续时间。
LF:最迟结束时间(Latest Finish),指为了保证整个项目按期完成的某项活动必须完成的最晚时间,取决于该项活动的所有紧后工作的最迟开始时间,由逆推法计算 LF = min{LS(successor activities)}。
LS:最迟开始时间(Latest Start),指为了保证整个项目按期完成的某项活动必须开始的最迟时间。LS = LF -DU,DU为该活动的持续时间。
TF:总时差(Total float time),指在不影响总工期的条件下,一个活动可以利用的机动时间。TF = LF - EF。
FF:自由时差(Free float time),指在不影响紧后工作最早开始时间的条件下,一个活动可能被延迟的时间。FF = min{ES(successor activities)} - EF。
由关键路径法得到的最早/最晚的开始/结束时间并不一定就是项目进度计划,而是把既定的参数(活动持续时间、逻辑关系、提前量、滞后量和其它制约条件)输入进度模型后所得到的结果,表明活动可以在该时段内实施。
早期关键路径法的表示方法都是箭线法(ADM,双代号网络图),随着计算机的发展,前导图(PDM,单代号网络图)逐渐成为主流方法。
1.3 关键路线的确定
总时差为零的工序就是关键工序,由他们就组成项目的关键路线。
二、关键路线法示例
案例:某项目的作业明细表
工作 | 紧前工作 | 作业时间 | 服务部门 | 工作 | 紧前工作 | 作业时间 | 服务部门 |
---|---|---|---|---|---|---|---|
A | - | 3 | IT | F | C | 4 | IT |
B | A | 3 | MKT | G | D,E | 4 | MKT |
C | A | 3 | ENG | H | E,F | 4 | PROD |
D | B | 8 | PROD | I | G,H | 2 | FIN |
E | B,C | 5 | FIN |
双代号网络图
三、关键路线法的计算(python)
3.1 数据的组织与输入
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from pandas import Timestamp
dictA = {'工作名称': 'A', '紧前工作': '-', '持续时间': 3, 'partment': 'IT'}
dictB = {'工作名称': 'B', '紧前工作': 'A', '持续时间': 3, 'partment': 'MKT'}
dictC = {'工作名称': 'C', '紧前工作': 'A', '持续时间': 3, 'partment': 'ENG'}
dictD = {'工作名称': 'D', '紧前工作': 'B', '持续时间': 8, 'partment': 'PROD'}
dictE = {'工作名称': 'E', '紧前工作': 'B,C', '持续时间': 5, 'partment': 'FIN'}
dictF = {'工作名称': 'F', '紧前工作': 'C', '持续时间': 4, 'partment': 'IT'}
dictG = {'工作名称': 'G', '紧前工作': 'D,E', '持续时间': 4, 'partment': 'MKT'}
dictH = {'工作名称': 'H', '紧前工作': 'E,F', '持续时间': 2, 'partment': 'PROD'}
dictI = {'工作名称': 'I', '紧前工作': 'H,G', '持续时间': 2, 'partment': 'FIN'}
list = [dictA, dictB, dictC, dictD, dictE, dictF, dictG, dictH, dictI]
3.2 时间参数的计算
# 最早开始时间
list1 = []
for i in range(len(list)):
listtmp = {'index': '', 'value': 0}
if list[i]['紧前工作'] == '-':
list1.append(0)
continue
tmp = list[i]["紧前工作"].split(',')
for x in tmp:
index = ord(x) - ord('A')
if listtmp['index'] == '':
listtmp['index'] = index
listtmp['value'] = list1[index]
else:
if list1[ord(x) - ord('A')] > listtmp['value']:
listtmp['index'] = index
listtmp['value'] = list1[index]
list1.append(list[listtmp['index']]['持续时间'] + listtmp['value'])
print(list1)
# 最早完成时间
list2 = []
for i in range(len(list1)):
list2.append(list1[i] + list[i]['持续时间'])
print(list2)
# 计算工期
Tp = list2[len(list2) - 1]
# 最迟开始时间
list3 = []
# 最迟完成时间
list4 = []
for i in range(len(list) - 1, -1, -1):
if i == len(list) - 1:
list4.append(Tp)
list3.append(Tp - list[i]['持续时间'])
continue
else:
min_value = 100
for j in range(len(list) - 1, i, -1):
tmp = list[j]["紧前工作"].split(',')
if list[i]['工作名称'] in tmp:
if min_value > list3[len(list) - j - 1]:
min_value = list3[len(list) - j - 1]
list4.append(min_value)
list3.append(list4[len(list) - i - 1] - list[i]['持续时间'])
list3.reverse()
list4.reverse()
print(list3)
print(list4)
# 总时差
list5 = []
for i in range(len(list)):
list5.append(list3[i] - list1[i])
print(list5)
# 自由时差
list6 = []
for i in range(len(list) - 1, -1, -1):
if i == len(list) - 1:
list6.append(Tp - list2[i])
continue
else:
min_value = 100
for j in range(len(list) - 1, i, -1):
tmp = list[j]["紧前工作"].split(',')
if list[i]['工作名称'] in tmp:
if min_value > list1[j]:
min_value = list1[j]
list6.append(min_value - list2[i])
list6.reverse()
print(list6)
工序时间参数计算结果如下表所示:
Task | Earliest_Start | Earliest_Finish | Lateat_Start | Latest_Finish | Total_Flote_Time | Free_Flote_Time |
---|---|---|---|---|---|---|
A | 0 | 3 | 0 | 3 | 0 | 0 |
B | 3 | 6 | 3 | 6 | 0 | 0 |
C | 3 | 6 | 6 | 9 | 3 | 0 |
D | 6 | 14 | 6 | 14 | 0 | 0 |
E | 6 | 11 | 9 | 14 | 3 | 0 |
F | 6 | 10 | 12 | 16 | 6 | 1 |
G | 14 | 18 | 14 | 18 | 0 | 0 |
H | 11 | 13 | 16 | 18 | 5 | 5 |
I | 18 | 20 | 18 | 20 | 0 | 0 |
3.3 关键路线的可视化——甘特图
#数据集成
df = pd.DataFrame()
df['start_num']=list1
df['end_num'] =list4
df['During']=0
df['Task']='a'
df['Department']='a'
df['Flexible']=0
for i in range(len(list)):
df.During[i] = list[i]['持续时间']
df.Task[i] = list[i]['工作名称']
df.Department[i] = list[i]['partment']
df.Flexible = 1-df.During/(df.end_num-df.start_num)
proj_start = df.start_num.min()
# days between start and end of each task
df['days_start_to_end'] = df.end_num - df.start_num
# days between start and current progression of each task
df['current_num'] = (df.days_start_to_end * (1-df.Flexible))
# 服务部门颜色
def color(row):
c_dict = {'MKT': '#E64646', 'FIN': '#E69646', 'ENG': '#34D05C', 'PROD': '#34D0C3', 'IT': '#3475D0'}
return c_dict[row['Department']]
df['color'] = df.apply(color, axis=1)
#甘特图
fig, ax = plt.subplots(1, figsize=(16,6))
# bars
ax.barh(df.Task, df.current_num, left=df.start_num, color=df.color)
ax.barh(df.Task, df.days_start_to_end, left=df.start_num, color=df.color, alpha=0.5)
# texts
for idx, row in df.iterrows():
ax.text(row.end_num+0.1, idx,
f"{int(row.Flexible*100)}%",
va='center', alpha=0.8)
##### LEGENDS #####
c_dict = {'MKT':'#E64646', 'FIN':'#E69646', 'ENG':'#34D05C', 'PROD':'#34D0C3', 'IT':'#3475D0'}
legend_elements = [Patch(facecolor=c_dict[i], label=i) for i in c_dict]
plt.legend(handles=legend_elements)
plt.show()
*!!!注意:图中百分数数字表示各工序机动时间占比。百分比为零的就是关键工序,由关键工序组成的路线就是关键路线。
四、总结
关键路径法(CPM),是一种算法用于调度的一组项目的活动。通常与程序评估和审查技术(PERT)结合使用。关键路径是通过确定最长的依存活动范围并测量从头到尾完成这些活动所需的时间来确定的。使用关键路径法的基本技术是构建项目管理计划,其中包括以下内容:
完成项目所需的所有活动的列表(通常在工作分解结构中分类),
每个活动完成所需的时间(持续时间),
活动之间的依赖关系以及
逻辑终点,例如里程碑或可交付项。
关键路径法使用这些值来计算计划的活动到逻辑终点或项目结束的最长路径,以及每个活动可以开始和完成而不必延长项目时间的最早和最新路径。该过程确定哪些活动是“关键的”(即,在最长的路径上),哪些活动具有“全部浮动”(即,可以在不延长项目时间的情况下将其延迟)。华罗庚教授为网络计划技术在我国的引进与发展做出了巨大的贡献,他的名字也将永远闪耀在运筹优化学科的历史长河中。美国著名数学史家贝特曼称:“华罗庚是中国的爱因斯坦,足够成为全世界所有著名科学院的院士”。
参考文献
1.(Python小白的数学建模课-21.关键路径法)[https://blog.csdn.net/youcans/article/details/118754623]
2. (项目管理:关键路径法)[https://baijiahao.baidu.com/s?id=1713675917353318226&wfr=spider&for=pc]
3. 根据逻辑关系图以及双代号网络图编写求时间参数(python版)
4. Python使用Matplotlib绘制甘特图的实践
网络计划技术——关键路线法(Python)的更多相关文章
- 【PMP】关键路径法与关键链法
通俗理解 关键路径法:把项目上的资源都事先全部分到每个活动上. 关键链法:每个活动不打富余,项目经理自己掌握资源,哪个成员执行过程中遇到困难,再给他单独分配资源. PMBOK定义 关键路径法:关键路径 ...
- python入门灵魂5问--python学习路线,python教程,python学哪些,python怎么学,python学到什么程度
一.python入门简介 对于刚接触python编程或者想学习python自动化的人来说,基本都会有以下python入门灵魂5问--python学习路线,python教程,python学哪些,pyth ...
- PMBOK及PMP考试精要
PROJECT MANAGEMENT KNOWLEDGE AREAS项目管理知识体系 2 PROJECT LIFE CYCLE / PROJECT MANAGEMENT PROCESS GROUPS项 ...
- 甘特图和PERT图
gantt图又叫甘特图.进度是按时间顺序计划活动的一个列表,我们称之为Gantt图,它有以下几个关键的成分:1.横跨图顶部排列的是日历表.2.最左边的一列包含了每项任务的标识号(ID).3.左边第二列 ...
- 【项目管理】 项目管理术语总结 (PMP培训笔记)
1. 项目管理简介 (1) 项目管理定义 项目管理定义 : 将 知识, 技能, 工具 与 技术 应用与项目活动, 以满足项目的要求; (2) 现代项目管理 现代项目管理与传统项目管理区别 : -- 传 ...
- PMBOK
项目章程的内容1. 基于项目干系人的需求和期望提出的要求.2. 项目必须满足的业务要求或产品需求.3. 项目的目的或项目立项的理由.4. 委派的项目经理及项目经理的权限级别.5. 概要的里程碑进度计划 ...
- python计算平面的法向-利用协方差矩阵求解特征值和特征向量
Obvious,最小特征值对应的特征向量为平面的法向 这个问题还有个关键是通过python求协方差矩阵的特征值和特征向量,np.linalg.eig()方法直接返回了特征值的向量和特征向量的矩阵 sc ...
- Python实现客观赋权法
本文从阐述Python实现客观赋权法的四种方式: 一. 熵权法 二. 因子分析权数法(FAM) 三. 主成分分析权数法(PCA) 四. 独立性权系数法 Python实现客观赋权法,在进行赋权前,先导入 ...
- Python基本概念及零碎知识点
1.python面向对象 类和对象是面向对象编程的两个主要方面.类创建一个新类型,而对象这个类的实例:这类似于你有一个int类型的变量,这存储整数的变量是int类的实例(对象)把握一点:在python ...
- Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式
一.组合 ''' 1.什么是组合 组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象 2.为何用组合 组合也是用来解决类与类直接代码冗余问题的 3.如何用组合 ''' # 继承减少代 ...
随机推荐
- echarts区域选择(brush)默认开启选择
api.dispatchAction({ // 刷选模式的开关.使用此 action 可将当前鼠标变为可刷选状态. 事实上,点击 toolbox 中的 brush 按钮时,就是通过这个 action, ...
- angular 父组件调用子组件的方法
- tp 获取器的使用中应该怎么append 自定义数据
$data = model('organization_area')->getListByNoPage($where, 'create_time asc');foreach ($data as ...
- 《JavaScript高级程序设计》Chapter04 变量,作用域,内存
原始值&引用值 原始值(primitive value):Undefined, Null, Boolean, Number, String, Symbol 按值访问,直接操作存储在变量中的实际 ...
- NOIP2011普及组
T2 统计单词数 也是一道经典题 字符串匹配 #include<iostream> #include<cstdio> #include<map> #include ...
- 试题管理/在线课程/模拟考试/能力评估报告/艾思在线考试系统www.aisisoft.cn
艾思软件发布在线考试系统, 可独立部署, 欢迎咨询索要测试账号 一. 主要特点: ThinkPHP前后端分离框式开发 主要功能有: 在线视频课程, 模拟考试, 在线考试, 能力评估报告, 考试历史错题 ...
- java map重写 转大写、转驼峰
/** * @author admin * @Description * 转大写 */ public class HashMapUpper<V> extends HashMap<St ...
- cmake使用boost静态库,错误提示 Could NOT find Boost (missing: Boost_INCLUDE_DIR) (Required is at least version "1.48")
使用的是Cmake-gui 编译. 问题出在C盘路径下找不到 Boost ,是否需要把boost的路径添加到系统Path 中? 任然不能解决. 更改源码: 找到下面这几行代码(你可以搜索) messa ...
- pip安装报错 cannot uninstall a distutils installed project
sudo pip install --ignore-installed xxx 在安装jupyter notebook的时候,遇到了这个问题,于是上网搜索,搜到了靠谱答案github解决方案 sudo ...
- Unity检测鼠标是否与UI交互
在Unity项目中,假设在鼠标按键时会触发游戏内的操作,但是在鼠标与UI进行交互时我们希望停止游戏中的操作,这是需要使用EventSystem中的方法来检测鼠标是否正在与UI交互 private bo ...