版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
现代库存管理:模型、算法与Python实现第16章某食品企业Z的分销网络库存优化实战16.1背景介绍企业Z是一家大型国际食品制造商:公司在中国建成了三级供应网络,有一个工厂,南北两个区域大仓,北方区域大仓下辖三个分销中心,南方区域大仓下辖五个分销中心,由分销中心向各区域的客户进行履约目前公司供应网络的库存管理主要采用单级的策略,每个仓采用覆盖自身提前期的目标库存策略来管理库存企业的发展趋势和转型需求:搭建了一套智慧供应链管理系统,将数据、算法和人工协作有机结合,加强供应网络的全局协同能力旨在研发一套分销网络的全局安全库存优化模型与算法,嵌入到其供应链管理系统当中16.1背景介绍挑选公司旗下的7个核心SKU,以这7个SKU的数据来探究如下两个问题:从全局优化的角度,这7个SKU的安全库存应该分别布局在哪些仓,以及相应的量应该是多少?全局优化后的安全库存策略相比于当前策略,能否显著降低总安全库存成本?研究方法步骤:将Z公司的分销网络建立成一个树网络对网络进行分析并建立相应的承诺服务模型利用动态规划算法求解最优的安全库存策略并分析其价值16.2数据导入及预处理#导入网络分析包
importnetworkxasnx
#导入数据分析包
importnumpyasnp
importpandasaspd
importmatplotlib.pyplotasplt
fromcollectionsimportdefaultdict
#导入第14章介绍过的几个算法
fromchapter14_network_basicimportfind_predecessors_dict,find_successors_dict,\
cal_cum_lt,cal_demand_bound
importwarnings
warnings.filterwarnings('ignore')#定义数据路径
data_dir=
'../../data/food/'
#读取分销网络的边数据
edge_df=pd.read_csv(data_dir+
'edge_data.csv')
#读取各SKU的生产时间数据
production_time_df=pd.read_csv(data_dir+
'production_time_data.csv')
#读取各节点的特征数据
feature_df=pd.read_csv(data_dir+
'feature_data.csv')
#读取需求节点(DC)的需求数据
demand_df=pd.read_csv(data_dir+
'demand_data.csv')16.2数据导入及预处理数据集概况:edge_df表:分销网络的边信息表’predecessor’:上游节点’successor’:下游节点’transport_time’:从上游节点到下游节点所需运输时间’quantity’:配比在分销网络中上下游只是运输传送关系,配比均为1predecessorsuccessortransport_timequantity0F000RDC001311F000RDC002212RDC001DC004113RDC001DC008214RDC001DC010315RDC002DC003116RDC002DC005217RDC002DC007118RDC002DC006319RDC002DC0092116.2数据导入及预处理数据集概况:利用NetworkX,对Z企业的分销网络进行可视化展示:16.2数据导入及预处理数据集概况:production_time_df表:7个SKU的生产时间sku_idproduction_time0SKU00031SKU00132SKU00213SKU00314SKU00425SKU00536SKU006316.2数据导入及预处理数据集概况:feature_df表:各个SKU在各节点(工厂,RDC和DC)的持货成本’hc’:持货成本’sla’:对客户承诺的服务时间’unit_id’:一个节点与一个SKU的组合node_idsku_idhcslaunit_id0DC003SKU0000.841DC003_SKU0001DC004SKU0000.871DC004_SKU0002DC005SKU0000.881DC005_SKU0003DC006SKU0000.884DC006_SKU0004DC007SKU0000.894DC007_SKU00016.2数据导入及预处理数据集概况:demand_df表:从历史销量数据中统计得到的各SKU在各个需求节点(各个DC)的需求均值和标准差node_idsku_idmeanstdunit_id0DC003SKU000108.767138146.382985DC003_SKU0001DC003SKU00191.416757142.366810DC003_SKU0012DC003SKU002129.607221209.291639DC003_SKU0023DC003SKU00397.410929174.465898DC003_SKU0034DC003SKU00492.281828139.159005DC003_SKU00416.2数据导入及预处理数据集预处理:以SKU’SKU000’为例将’SKU000’的相关数据提取出来,并进行预处理,计算出每个节点的累计提前期计算每个节点覆盖时间的需求上界及安全库存量,计算周期服务水平为0.95对应的需求上界将后续要反复使用的数据转换成字典格式数据集预处理代码如下:sku=
'SKU000'
#将sku对应的需求信息提取出来
sku_demand_df=demand_df[demand_df['sku_id']==sku]
#分销网络的配比均为1
qty_dict={(pred,succ):qforpred,succ,qin
edge_df[['predecessor','successor','quantity']].values}
16.2数据导入及预处理数据集预处理代码:#根据sku对应的生产加工时间,计算每个节点的累计提前期
sku_production_time=int(production_time_df[
production_time_df['sku_id']==sku][
'production_time'])
lt_dict=dict(zip(edge_df['successor'],edge_df['transport_time']))
lt_dict.update({'F000':sku_production_time})
lt_df=pd.DataFrame.from_dict(
lt_dict,orient='index').reset_index().rename(
columns={'index':'node_id',0:'lt'})
cum_lt_dict=cal_cum_lt(edge_df[['predecessor','successor']].values,lt_dict)
cum_lt_df=pd.DataFrame.from_dict(
cum_lt_dict,orient='index').reset_index().rename(
columns={'index':'node_id',0:'cum_lt'})
#将sku对应的节点属性表读取出来,并将提前期与累计提前期合并到一张表上,方便分析
sku_node_df=feature_df[feature_df['sku_id']==sku]
sku_node_df=sku_node_df.merge(lt_df,on='node_id',how='left')
sku_node_df=sku_node_df.merge(cum_lt_df,on='node_id',how='left')
print(sku_node_df)16.2数据导入及预处理数据集预处理代码:#累计提前期
cum_lt_dict=dict(zip(sku_node_df['node_id'],sku_node_df['cum_lt']))
#提前期
lt_dict=dict(zip(sku_node_df['node_id'],sku_node_df['lt']))
#每个节点对应覆盖时间的安全库存量
ss_ct_dict={(node,time):ssfornode,time,ssin
sku_demand_bound_df[['node_id','time','ss_qty']].values}
#持货成本
hc_dict=dict(zip(sku_node_df['node_id'],sku_node_df['hc']))
#sla
sla_df=sku_node_df[sku_node_df['sla'].notna()]
sla_dict=dict(zip(sla_df['node_id'],sla_df['sla']))#将sku对应的节点属性表读取出来,并将提前期与累计提前期合并到一张表上,方便分析
sku_node_df=feature_df[feature_df['sku_id']==sku]
sku_node_df=sku_node_df.merge(lt_df,on='node_id',how='left')
sku_node_df=sku_node_df.merge(cum_lt_df,on='node_id',how='left')
print(sku_node_df)16.3应用动态规划算法求解最优策略
16.3应用动态规划算法求解最优策略对网络中的节点进行排序:找到满足除了根节点之外,每个节点至多有一个相邻节点在该节点之后的序列defsort(graph):
#将图转化成无向图
un_di_graph=graph.to_undirected()
#计算图中节点总数
nodes_num=len(un_di_graph.nodes())
sorted_list=[]
#如果还有节点未被加入排序,则继续
whilelen(sorted_list)<nodes_num:
#调用NetworkX计算节点的度数
degree_dict={node:vfornode,vinun_di_graph.degree()}
#将最多只有一个节点与其相邻的节点加入排序
border_nodes=[nodefornode,degreeindegree_dict.items()if
degree<=
1]
sorted_list.extend(border_nodes)
#从图中移除已排序的节点
un_di_graph.remove_nodes_from(border_nodes)
returnsorted_list
sorted_list=sort(graph)
print(sorted_list)16.3应用动态规划算法求解最优策略
defget_parent_dict(graph,sorted_list):
un_di_graph=graph.to_undirected()
#找到每个节点相邻的节点集合
neighbors_dict={node:list(un_di_graph.neighbors(node))
fornodeinun_di_graph.nodes()}
#对节点进行标号,方便查询排序先后
labeled_dict={node:ifori,nodeinenumerate(sorted_list)}
parent_dict={}
fornodeinsorted_list:
#对于每个节点,用c表示在该节点之后的相邻节点
c=
0
forneighborinneighbors_dict[node]:
iflabeled_dict[neighbor]>labeled_dict[node]:
c+=
1
#找到在该节点之后的相邻节点后,将其记录
parent_dict[node]=neighbor
#如果超过1,说明排序有误
ifc>
1:
raise
Exception('wronglabel')
returnparent_dict
parent_dict=get_parent_dict(graph,sorted_list)16.3应用动态规划算法求解最优策略判断每个节点应该使用哪一类成本函数:定义函数classif_node用于判断节点应当使用哪种成本函数,并记录每个节点的子树信息defclassify_node(graph,edge_df,sorted_list):
#定义上下游字典
pred_dict=find_predecessors_dict(
edges=edge_df[['predecessor','successor']].values)
succ_dict=find_successors_dict(
edges=edge_df[['predecessor','successor']].values)
un_di_graph=graph.to_undirected()
neighbors_dict={node:list(un_di_graph.neighbors(node))
fornodeinun_di_graph.nodes()}
labeled_dict={node:ifori,nodeinenumerate(sorted_list)}
to_eva_f_list=[]
to_eva_g_list=[]
fornodeinsorted_list:
forneighborinneighbors_dict[node]:
iflabeled_dict[neighbor]>labeled_dict[node]:
ifneighborinsucc_dict[node]:
#如果p(j)在节点j下游,则将节点标记为使用f成本函数
to_eva_f_list.append(node)
16.3应用动态规划算法求解最优策略判断每个节点应该使用哪一类成本函数:定义函数classif_node用于判断节点应当使用哪种成本函数,并记录每个节点的子树信息elifneighborinpred_dict[node]:
#如果p(j)在节点j上游,则将节点标记为使用g成本函数
to_eva_g_list.append(node)
else:
raise
Exception('wrong')
#记录子树信息
sub_pred_dict={node:[pforpinpred_dict[node]
iflabeled_dict[p]<labeled_dict[node]]
fornodeinsorted_list}
sub_succ_dict={node:[sforsinsucc_dict[node]
iflabeled_dict[s]<labeled_dict[node]]
fornodeinsorted_list}
returnto_eva_f_list,to_eva_g_list,sub_pred_dict,sub_succ_dict
to_eva_f_list,to_eva_g_list,sub_pred_dict,sub_succ_dict=classify_node(
graph,edge_df,sorted_list)16.3应用动态规划算法求解最优策略
16.3应用动态规划算法求解最优策略数据准备并初始化动态规划表:代码如下S_index={
node:np.arange(0,min(sla_dict.get(node,9999),cum_lt_dict[node])+
1)
fornodeinsorted_list}
SI_index={node:np.arange(0,cum_lt_dict[node]-lt_dict[node]+
1)
fornodeinsorted_list}
CT_index={node:np.arange(0,cum_lt_dict[node]+
1)fornodeinsorted_list}on_hand_cost={(node,CT):hc_dict[node]*ss_ct_dict[node,CT]
fornodeinsorted_listforCTinCT_index[node]}#cost_record记录出每个节点,每种策略组合(S,SI)下的成本
cost_record=defaultdict(dict)
#f_cost记录在给定S的情况下,p(j)在节点下游的节点的子树上的最小库存成本
f_cost={(node,S):-float('inf')fornodeinto_eva_f_listforSin
S_index[node]}
#f_argmin记录f_cost的最小库存成本所对应的SI
f_argmin={(node,S):-float('inf')fornodeinto_eva_f_listforSin
S_index[node]}
#g_cost记录在给定SI的情况下,p(j)在节点上游的节点的子树上的最小库存成本
g_cost={(node,SI):-float('inf')fornodeinto_eva_g_listforSIin
SI_index[node]}
#g_argmin记录g_cost的最小库存成本所对应的S
g_argmin={(node,SI):-float('inf')fornodeinto_eva_g_listforSIin
SI_index[node]}16.3应用动态规划算法求解最优策略
16.3应用动态规划算法求解最优策略
defevaluate_f(node,S):
#测试全部可能的SI
to_test_SI=np.arange(max(0,S-lt_dict[node]),
cum_lt_dict[node]-lt_dict[node]+
1)
forSIinto_test_SI:
#计算当前策略组合下的覆盖时间
CT=SI+lt_dict[node]-S
#计算当前策略组合下的库存成本
#首先是自身库存成本
cost_record[node][S,SI]=on_hand_cost[node,CT]
#如果节点有上游节点,那么需要加总上游节点子树对应的成本
iflen(sub_pred_dict[node])>
0:
forpredinsub_pred_dict[node]:
cost_record[node][S,SI]+=min(
[f_cost[pred,s]forsinS_index[pred]ifs<=SI])
#如果节点有下游节点,那么需要加总下游节点子树对应的成本
iflen(sub_succ_dict[node])>
0:
forsuccinsub_succ_dict[node]:
cost_record[node][S,SI]+=min(
[g_cost[succ,si]forsiinSI_index[succ]ifsi>=S])
#找到给定S情况下的最优的SI
cost_SI_dict={si:cost_record[node][S,si]forsiinto_test_SI}
best_SI=min(cost_SI_dict,key=cost_SI_dict.get)
#将成本记录到f_cost,将最优的SI记录到f_argmin
f_cost[node,S]=cost_SI_dict[best_SI]
f_argmin[node,S]=best_SI16.3应用动态规划算法求解最优策略
defevaluate_g(node,SI):
#测试全部可能的S
to_test_S=np.arange(0,min(sla_dict.get(node,9999),
SI+lt_dict[node])+
1)
forSinto_test_S:
#计算当前策略组合下的覆盖时间
CT=SI+lt_dict[node]-S
#计算当前策略组合下的库存成本
#首先是自身库存成本
cost_record[node][S,SI]=on_hand_cost[node,CT]
#如果节点有上游节点,那么需要加总上游节点子树对应的成本
iflen(sub_pred_dict[node])>
0:
forpredinsub_pred_dict[node]:
cost_record[node][S,SI]+=min(
[f_cost[pred,s]forsinS_index[pred]ifs<=SI])
#如果节点有下游节点,那么需要加总下游节点子树对应的成本
iflen(sub_succ_dict[node])>
0:
forsuccinsub_succ_dict[node]:
cost_record[node][S,SI]+=min(
[g_cost[succ,si]forsiinSI_index[succ]ifsi>=S])
#找到给定SI情况下的最优的S
cost_S_dict={s:cost_record[node][s,SI]forsinto_test_S}
best_S=min(cost_S_dict,key=cost_S_dict.get)
#将成本记录到g_cost,将最优的S记录到g_argmin
g_cost[node,SI]=cost_S_dict[best_S]
g_argmin[node,SI]=best_S16.3应用动态规划算法求解最优策略根据排序,遍历计算最优成本#遍历节点,除了最后一个节点外
fornodeinsorted_list[:-1]:
#如果p(j)在节点下游,则对于所有可能的S,计算f函数
ifnodeinto_eva_f_list:
forSinS_index[node]:
evaluate_f(node,S)
#如果p(j)在节点上游,则对于所有可能的S,计算g函数
ifnodeinto_eva_g_list:
forSIinSI_index[node]:
evaluate_g(node,SI)
#对于排序中最后一个节点,对于所有可能的SI,计算g函数
end_node=sorted_list[-1]
forSIinSI_index[end_node]:
evaluate_g(end_node,SI)16.3应用动态规划算法求解最优策略
end_g_cost_dict={si:g_cost[end_node,si]forsiinSI_index[end_node]}
end_node_SI=min(end_g_cost_dict,key=end_g_cost_dict.get)
end_node_S=g_argmin[end_node,end_node_SI]16.3应用动态规划算法求解最优策略使用回溯法找到最优策略:#定义最优策略字典
opt_sol={'S':{},'SI':{},'CT':{}}
#将最后一个节点的最优值存贮在最优策略中
opt_sol['SI'][end_node]=end_node_SI
opt_sol['S'][end_node]=end_node_S
#从序列的倒数第二个节点开始反向遍历
fornodeinsorted_list[-2::-1]:
parent_node=parent_dict[node]
#如果p(j)在节点上游,则SI_j^*=S_{p(j)}^*,S_j^*=argming_j(SI_j^*)
ifnodeinsub_succ_dict[parent_node]:
node_SI=opt_sol['S'][parent_node]
node_S=g_argmin[node,node_SI]
#如果p(j)在节点下游,则S_j^*=SI_{p(j)}^*,SI_j^*=argminf_j(S_j^*)
elifnodeinsub_pred_dict[parent_node]:
node_S=min(opt_sol['SI'][parent_node],S_index[node].max())
node_SI=f_argmin[node,node_S]
else:
raise
Exception
opt_sol['S'][n
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 抖音单品爆款分析:商务男装衬衫POLO衫-知衣数据
- 2024年人教版七年级英语下册第八单元课堂练习题及答案 第4课时 Section B(1a-1d)
- 高考物理大一轮复习 课后限时集训13 万有引力与航天-人教版高三全册物理试题
- 高考生物一轮复习 第一编 考点通关 单元测试(三)细胞的生命历程(含解析)-人教版高三全册生物试题
- 高考物理一轮复习 热点突破提升练7 电路知识综合应用-人教版高三物理试题
- 2024届湖南省“一起考”大联考高三下学期3月模拟考试(模拟一)地理(模拟卷一)答案
- 陕西省宝鸡市麟游县部分小学2023-2024学年一年级下学期期中语文试卷
- 光纤识别仪校准规范报批稿
- 2024年冀教版七年级英语下册Unit 4复习题及答案
- 河南省驻马店市汝南县2024届九年级下学期中考一模数学试卷(含解析)
- 徐迟《黄山记》原文阅读
- XRD晶体结构分析演示文稿
- YY 1289-2022激光治疗设备眼科激光光凝仪
- GB/T 5173-1995表面活性剂和洗涤剂阴离子活性物的测定直接两相滴定法
- GB/T 4852-2002压敏胶粘带初粘性试验方法(滚球法)
- FZ/T 13019-2007色织氨纶弹力布
- ERCP讲义教学课件
- 超星尔雅学习通【对话诺奖大师(美国加州理工学院)】章节测试含答案
- 肥料质量管理制度
- 高速公路机电系统培训课件
- AC-20型沥青混合料生产配合比
评论
0/150
提交评论