版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
現(xiàn)代庫存管理:模型、算法與Python實(shí)現(xiàn)第16章某食品企業(yè)Z的分銷網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)16.1背景介紹企業(yè)Z是一家大型國際食品制造商:公司在中國建成了三級供應(yīng)網(wǎng)絡(luò),有一個(gè)工廠,南北兩個(gè)區(qū)域大倉,北方區(qū)域大倉下轄三個(gè)分銷中心,南方區(qū)域大倉下轄五個(gè)分銷中心,由分銷中心向各區(qū)域的客戶進(jìn)行履約目前公司供應(yīng)網(wǎng)絡(luò)的庫存管理主要采用單級的策略,每個(gè)倉采用覆蓋自身提前期的目標(biāo)庫存策略來管理庫存企業(yè)的發(fā)展趨勢和轉(zhuǎn)型需求:搭建了一套智慧供應(yīng)鏈管理系統(tǒng),將數(shù)據(jù)、算法和人工協(xié)作有機(jī)結(jié)合,加強(qiáng)供應(yīng)網(wǎng)絡(luò)的全局協(xié)同能力旨在研發(fā)一套分銷網(wǎng)絡(luò)的全局安全庫存優(yōu)化模型與算法,嵌入到其供應(yīng)鏈管理系統(tǒng)當(dāng)中16.1背景介紹挑選公司旗下的7個(gè)核心SKU,以這7個(gè)SKU的數(shù)據(jù)來探究如下兩個(gè)問題:從全局優(yōu)化的角度,這7個(gè)SKU的安全庫存應(yīng)該分別布局在哪些倉,以及相應(yīng)的量應(yīng)該是多少?全局優(yōu)化后的安全庫存策略相比于當(dāng)前策略,能否顯著降低總安全庫存成本?研究方法步驟:將Z公司的分銷網(wǎng)絡(luò)建立成一個(gè)樹網(wǎng)絡(luò)對網(wǎng)絡(luò)進(jìn)行分析并建立相應(yīng)的承諾服務(wù)模型利用動態(tài)規(guī)劃算法求解最優(yōu)的安全庫存策略并分析其價(jià)值16.2數(shù)據(jù)導(dǎo)入及預(yù)處理#導(dǎo)入網(wǎng)絡(luò)分析包
importnetworkxasnx
#導(dǎo)入數(shù)據(jù)分析包
importnumpyasnp
importpandasaspd
importmatplotlib.pyplotasplt
fromcollectionsimportdefaultdict
#導(dǎo)入第14章介紹過的幾個(gè)算法
fromchapter14_network_basicimportfind_predecessors_dict,find_successors_dict,\
cal_cum_lt,cal_demand_bound
importwarnings
warnings.filterwarnings('ignore')#定義數(shù)據(jù)路徑
data_dir=
'../../data/food/'
#讀取分銷網(wǎng)絡(luò)的邊數(shù)據(jù)
edge_df=pd.read_csv(data_dir+
'edge_data.csv')
#讀取各SKU的生產(chǎn)時(shí)間數(shù)據(jù)
production_time_df=pd.read_csv(data_dir+
'production_time_data.csv')
#讀取各節(jié)點(diǎn)的特征數(shù)據(jù)
feature_df=pd.read_csv(data_dir+
'feature_data.csv')
#讀取需求節(jié)點(diǎn)(DC)的需求數(shù)據(jù)
demand_df=pd.read_csv(data_dir+
'demand_data.csv')16.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:edge_df表:分銷網(wǎng)絡(luò)的邊信息表’predecessor’:上游節(jié)點(diǎn)’successor’:下游節(jié)點(diǎn)’transport_time’:從上游節(jié)點(diǎn)到下游節(jié)點(diǎn)所需運(yùn)輸時(shí)間’quantity’:配比在分銷網(wǎng)絡(luò)中上下游只是運(yùn)輸傳送關(guān)系,配比均為1predecessorsuccessortransport_timequantity0F000RDC001311F000RDC002212RDC001DC004113RDC001DC008214RDC001DC010315RDC002DC003116RDC002DC005217RDC002DC007118RDC002DC006319RDC002DC0092116.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:利用NetworkX,對Z企業(yè)的分銷網(wǎng)絡(luò)進(jìn)行可視化展示:16.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:production_time_df表:7個(gè)SKU的生產(chǎn)時(shí)間sku_idproduction_time0SKU00031SKU00132SKU00213SKU00314SKU00425SKU00536SKU006316.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:feature_df表:各個(gè)SKU在各節(jié)點(diǎn)(工廠,RDC和DC)的持貨成本’hc’:持貨成本’sla’:對客戶承諾的服務(wù)時(shí)間’unit_id’:一個(gè)節(jié)點(diǎn)與一個(gè)SKU的組合node_idsku_idhcslaunit_id0DC003SKU0000.841DC003_SKU0001DC004SKU0000.871DC004_SKU0002DC005SKU0000.881DC005_SKU0003DC006SKU0000.884DC006_SKU0004DC007SKU0000.894DC007_SKU00016.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:demand_df表:從歷史銷量數(shù)據(jù)中統(tǒng)計(jì)得到的各SKU在各個(gè)需求節(jié)點(diǎn)(各個(gè)DC)的需求均值和標(biāo)準(zhǔn)差node_idsku_idmeanstdunit_id0DC003SKU000108.767138146.382985DC003_SKU0001DC003SKU00191.416757142.366810DC003_SKU0012DC003SKU002129.607221209.291639DC003_SKU0023DC003SKU00397.410929174.465898DC003_SKU0034DC003SKU00492.281828139.159005DC003_SKU00416.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集預(yù)處理:以SKU’SKU000’為例將’SKU000’的相關(guān)數(shù)據(jù)提取出來,并進(jìn)行預(yù)處理,計(jì)算出每個(gè)節(jié)點(diǎn)的累計(jì)提前期計(jì)算每個(gè)節(jié)點(diǎn)覆蓋時(shí)間的需求上界及安全庫存量,計(jì)算周期服務(wù)水平為0.95對應(yīng)的需求上界將后續(xù)要反復(fù)使用的數(shù)據(jù)轉(zhuǎn)換成字典格式數(shù)據(jù)集預(yù)處理代碼如下:sku=
'SKU000'
#將sku對應(yīng)的需求信息提取出來
sku_demand_df=demand_df[demand_df['sku_id']==sku]
#分銷網(wǎng)絡(luò)的配比均為1
qty_dict={(pred,succ):qforpred,succ,qin
edge_df[['predecessor','successor','quantity']].values}
16.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集預(yù)處理代碼:#根據(jù)sku對應(yīng)的生產(chǎn)加工時(shí)間,計(jì)算每個(gè)節(jié)點(diǎn)的累計(jì)提前期
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對應(yīng)的節(jié)點(diǎn)屬性表讀取出來,并將提前期與累計(jì)提前期合并到一張表上,方便分析
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數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集預(yù)處理代碼:#累計(jì)提前期
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']))
#每個(gè)節(jié)點(diǎn)對應(yīng)覆蓋時(shí)間的安全庫存量
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對應(yīng)的節(jié)點(diǎn)屬性表讀取出來,并將提前期與累計(jì)提前期合并到一張表上,方便分析
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應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略
16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略對網(wǎng)絡(luò)中的節(jié)點(diǎn)進(jìn)行排序:找到滿足除了根節(jié)點(diǎn)之外,每個(gè)節(jié)點(diǎn)至多有一個(gè)相鄰節(jié)點(diǎn)在該節(jié)點(diǎn)之后的序列defsort(graph):
#將圖轉(zhuǎn)化成無向圖
un_di_graph=graph.to_undirected()
#計(jì)算圖中節(jié)點(diǎn)總數(shù)
nodes_num=len(un_di_graph.nodes())
sorted_list=[]
#如果還有節(jié)點(diǎn)未被加入排序,則繼續(xù)
whilelen(sorted_list)<nodes_num:
#調(diào)用NetworkX計(jì)算節(jié)點(diǎn)的度數(shù)
degree_dict={node:vfornode,vinun_di_graph.degree()}
#將最多只有一個(gè)節(jié)點(diǎn)與其相鄰的節(jié)點(diǎn)加入排序
border_nodes=[nodefornode,degreeindegree_dict.items()if
degree<=
1]
sorted_list.extend(border_nodes)
#從圖中移除已排序的節(jié)點(diǎn)
un_di_graph.remove_nodes_from(border_nodes)
returnsorted_list
sorted_list=sort(graph)
print(sorted_list)16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略
defget_parent_dict(graph,sorted_list):
un_di_graph=graph.to_undirected()
#找到每個(gè)節(jié)點(diǎn)相鄰的節(jié)點(diǎn)集合
neighbors_dict={node:list(un_di_graph.neighbors(node))
fornodeinun_di_graph.nodes()}
#對節(jié)點(diǎn)進(jìn)行標(biāo)號,方便查詢排序先后
labeled_dict={node:ifori,nodeinenumerate(sorted_list)}
parent_dict={}
fornodeinsorted_list:
#對于每個(gè)節(jié)點(diǎn),用c表示在該節(jié)點(diǎn)之后的相鄰節(jié)點(diǎn)
c=
0
forneighborinneighbors_dict[node]:
iflabeled_dict[neighbor]>labeled_dict[node]:
c+=
1
#找到在該節(jié)點(diǎn)之后的相鄰節(jié)點(diǎn)后,將其記錄
parent_dict[node]=neighbor
#如果超過1,說明排序有誤
ifc>
1:
raise
Exception('wronglabel')
returnparent_dict
parent_dict=get_parent_dict(graph,sorted_list)16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略判斷每個(gè)節(jié)點(diǎn)應(yīng)該使用哪一類成本函數(shù):定義函數(shù)classif_node用于判斷節(jié)點(diǎn)應(yīng)當(dāng)使用哪種成本函數(shù),并記錄每個(gè)節(jié)點(diǎn)的子樹信息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)在節(jié)點(diǎn)j下游,則將節(jié)點(diǎn)標(biāo)記為使用f成本函數(shù)
to_eva_f_list.append(node)
16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略判斷每個(gè)節(jié)點(diǎn)應(yīng)該使用哪一類成本函數(shù):定義函數(shù)classif_node用于判斷節(jié)點(diǎn)應(yīng)當(dāng)使用哪種成本函數(shù),并記錄每個(gè)節(jié)點(diǎn)的子樹信息elifneighborinpred_dict[node]:
#如果p(j)在節(jié)點(diǎn)j上游,則將節(jié)點(diǎn)標(biāo)記為使用g成本函數(shù)
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應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略
16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略數(shù)據(jù)準(zhǔn)備并初始化動態(tài)規(guī)劃表:代碼如下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記錄出每個(gè)節(jié)點(diǎn),每種策略組合(S,SI)下的成本
cost_record=defaultdict(dict)
#f_cost記錄在給定S的情況下,p(j)在節(jié)點(diǎn)下游的節(jié)點(diǎn)的子樹上的最小庫存成本
f_cost={(node,S):-float('inf')fornodeinto_eva_f_listforSin
S_index[node]}
#f_argmin記錄f_cost的最小庫存成本所對應(yīng)的SI
f_argmin={(node,S):-float('inf')fornodeinto_eva_f_listforSin
S_index[node]}
#g_cost記錄在給定SI的情況下,p(j)在節(jié)點(diǎn)上游的節(jié)點(diǎn)的子樹上的最小庫存成本
g_cost={(node,SI):-float('inf')fornodeinto_eva_g_listforSIin
SI_index[node]}
#g_argmin記錄g_cost的最小庫存成本所對應(yīng)的S
g_argmin={(node,SI):-float('inf')fornodeinto_eva_g_listforSIin
SI_index[node]}16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略
16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略
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:
#計(jì)算當(dāng)前策略組合下的覆蓋時(shí)間
CT=SI+lt_dict[node]-S
#計(jì)算當(dāng)前策略組合下的庫存成本
#首先是自身庫存成本
cost_record[node][S,SI]=on_hand_cost[node,CT]
#如果節(jié)點(diǎn)有上游節(jié)點(diǎn),那么需要加總上游節(jié)點(diǎn)子樹對應(yīng)的成本
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])
#如果節(jié)點(diǎn)有下游節(jié)點(diǎn),那么需要加總下游節(jié)點(diǎn)子樹對應(yīng)的成本
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情況下的最優(yōu)的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,將最優(yōu)的SI記錄到f_argmin
f_cost[node,S]=cost_SI_dict[best_SI]
f_argmin[node,S]=best_SI16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略
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:
#計(jì)算當(dāng)前策略組合下的覆蓋時(shí)間
CT=SI+lt_dict[node]-S
#計(jì)算當(dāng)前策略組合下的庫存成本
#首先是自身庫存成本
cost_record[node][S,SI]=on_hand_cost[node,CT]
#如果節(jié)點(diǎn)有上游節(jié)點(diǎn),那么需要加總上游節(jié)點(diǎn)子樹對應(yīng)的成本
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])
#如果節(jié)點(diǎn)有下游節(jié)點(diǎn),那么需要加總下游節(jié)點(diǎn)子樹對應(yīng)的成本
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情況下的最優(yōu)的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,將最優(yōu)的S記錄到g_argmin
g_cost[node,SI]=cost_S_dict[best_S]
g_argmin[node,SI]=best_S16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略根據(jù)排序,遍歷計(jì)算最優(yōu)成本#遍歷節(jié)點(diǎn),除了最后一個(gè)節(jié)點(diǎn)外
fornodeinsorted_list[:-1]:
#如果p(j)在節(jié)點(diǎn)下游,則對于所有可能的S,計(jì)算f函數(shù)
ifnodeinto_eva_f_list:
forSinS_index[node]:
evaluate_f(node,S)
#如果p(j)在節(jié)點(diǎn)上游,則對于所有可能的S,計(jì)算g函數(shù)
ifnodeinto_eva_g_list:
forSIinSI_index[node]:
evaluate_g(node,SI)
#對于排序中最后一個(gè)節(jié)點(diǎn),對于所有可能的SI,計(jì)算g函數(shù)
end_node=sorted_list[-1]
forSIinSI_index[end_node]:
evaluate_g(end_node,SI)16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略
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應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略使用回溯法找到最優(yōu)策略:#定義最優(yōu)策略字典
opt_sol={'S':{},'SI':{},'CT':{}}
#將最后一個(gè)節(jié)點(diǎn)的最優(yōu)值存貯在最優(yōu)策略中
opt_sol['SI'][end_node]=end_node_SI
opt_sol['S'][end_node]=end_node_S
#從序列的倒數(shù)第二個(gè)節(jié)點(diǎn)開始反向遍歷
fornodeinsorted_list[-2::-1]:
parent_node=parent_dict[node]
#如果p(j)在節(jié)點(diǎn)上游,則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)在節(jié)點(diǎn)下游,則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'][node]=node_S
opt_sol['SI'][node]=node_SI
#根據(jù)最優(yōu)的S^*和SI^*,計(jì)算最優(yōu)的CT^*
opt_sol['CT']={node:opt_sol['SI'][node]+lt_dict[node]-
opt_sol['S'][node]fornodeinsorted_list}16.3應(yīng)用動態(tài)規(guī)劃算法求解最優(yōu)策略策略成本比較:計(jì)算策略的安全庫存成本,并與使用單點(diǎn)的方法設(shè)置安全庫存的策略進(jìn)行比較#計(jì)算網(wǎng)絡(luò)最優(yōu)策略的成本
opt_ss_dict={node:ss_ct_dict.get((node,CT),0)
fornode,CTinopt_sol['CT'].items()}
opt_ss_cost=sum([hc_dict[node]*opt_ss_dict[node]
fornodeinsku_node_df['node_id']])
#計(jì)算單級策略的安全庫存成本
single_ct_dict={node:max(0,lt_dict[node]-sla_dict[node])
ifnodeinsla_dict.keys()elselt_dict[node]
fornodeinsku_node_df['node_id']}
single_ss_dict={node:ss_ct_dict.get((node,CT),0)
fornode,CTinsingle_ct_dict.items()}
single_ss_cost=sum([hc_dict[node]*single_ss_dict[node]
fornodeinsku_node_df['node_id']])
print('使用單級策略的安全庫存成本為%.2f'
%single_ss_cost)
print('使用網(wǎng)絡(luò)最優(yōu)策略的安全庫存成本為%.2f,相比于單級策略,降低成本%.2f'
%(opt_ss_cost,single_ss_cost-opt_ss_cost))使用單級策略的安全庫存成本為1263.35
使用網(wǎng)絡(luò)最優(yōu)策略的安全庫存成本為1110.80,相比于單級策略,降低成本152.5416.4拓展思考在本案例中,工廠和RDC只向下游的DC供貨,自身并不直接面向客戶需求。實(shí)際中,一些企業(yè)會建立工廠直發(fā)渠道,而RDC需要覆蓋一定區(qū)域的客戶需求。此時(shí),應(yīng)該如何對模型進(jìn)行改進(jìn)?本案例假設(shè)同一SKU在不同DC的需求是相互獨(dú)立的。如果不同DC的需求之間存在相關(guān)性,應(yīng)該如何將需求的相關(guān)性考慮到模型中?本案例將需求看作平穩(wěn)的過程來建模,如果需求具有非平穩(wěn)性(例如,季節(jié)性,趨勢性),安全庫存又該如何優(yōu)化?現(xiàn)代庫存管理:模型、算法與Python實(shí)現(xiàn)第17章某家電企業(yè)H的制造網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)17.1背景介紹企業(yè)H是一家大型的家電制造商,旗下產(chǎn)品覆蓋了絕大部分的家庭電器:同一種原材料一般支撐多個(gè)半成品、成品的生產(chǎn),H公司一直以來主要在原材料上放置安全庫存企業(yè)的發(fā)展趨勢和轉(zhuǎn)型需求:各大渠道商對工廠的交付時(shí)間有了更高的要求,需要將制造網(wǎng)絡(luò)中的安全庫存前置17.1背景介紹公司挑選兩款“明星”產(chǎn)品以及它們的生產(chǎn)涉及的所有半成品和原材料,利用物料清單、各物料的持貨成本、成品需求的預(yù)測均值和誤差,以及工廠對客戶的承諾服務(wù)時(shí)間等數(shù)據(jù),以這兩個(gè)產(chǎn)品的制造網(wǎng)絡(luò)為基礎(chǔ),搭建出全網(wǎng)絡(luò)安全庫存優(yōu)化方案的原型,探究如下三個(gè)問題:應(yīng)該選擇網(wǎng)絡(luò)的哪些節(jié)點(diǎn)放置安全庫存(位置),以及放置多少安全庫存(量)?與安全庫存全部前置在成品的策略相比,全局最優(yōu)的策略能否顯著降低總安全庫存成本?對客戶的承諾服務(wù)時(shí)間對總安全庫存成本的影響有多大?由于制造中存在很多通用件,在本案例中,使用有向無環(huán)圖對家電企業(yè)H的兩個(gè)成品的制造網(wǎng)絡(luò)進(jìn)行建模,并使用分段線性函數(shù)近似算法,建立混合整數(shù)規(guī)劃來求解相應(yīng)的承諾服務(wù)模型17.2數(shù)據(jù)導(dǎo)入及預(yù)處理#導(dǎo)入網(wǎng)絡(luò)分析包
importnetworkxasnx
#導(dǎo)入數(shù)據(jù)分析包
importpandasaspd
#導(dǎo)入第10章的幾個(gè)算法
fromchapter14_network_basicimportcal_cum_lt,cal_demand_bound
#導(dǎo)入copt優(yōu)化求解包
fromcoptpyimport*
importmatplotlib.pyplotasplt
importseabornassns
sns.set_theme(style='darkgrid')
importwarnings
warnings.filterwarnings('ignore')#定義數(shù)據(jù)路徑
data_dir=
'../../data/manufacture/'
#讀取兩個(gè)需求節(jié)點(diǎn)(成品)的需求數(shù)據(jù)
demand_df=pd.read_csv(data_dir+
'manufacture_demand_df.csv')
#讀取制造網(wǎng)絡(luò)的節(jié)點(diǎn)數(shù)據(jù)
node_df=pd.read_csv(data_dir+
'manufacture_node_df.csv')
#讀取制造網(wǎng)絡(luò)的邊數(shù)據(jù)
edge_df=pd.read_csv(data_dir+
'manufacture_edge_df.csv')17.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:demand_df表:展示了兩個(gè)成品的需求信息node_idmeanstd0N00190163.1164901.3218181N00166113.9650239.74188217.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:edge_df表:BOM的邊信息表’predecessor’:上游節(jié)點(diǎn)’successor’:下游節(jié)點(diǎn)’quantity’:配比node_df表:BOM的節(jié)點(diǎn)信息表’node_id’:節(jié)點(diǎn)的id’lt’:提前期’hc’:單位持貨成本’sla’:對客戶的承諾服務(wù)時(shí)間predecessorsuccessorquantity0N002230N0019011.0001N001693N0019011.0002N001664N0016931.2003N000519N0016930.0014N000416N0016930.001node_idlthcsla0N00160840.478034NaN1N00274740.860900NaN2N00302420.483988NaN3N00096860.311728NaN4N00052890.807896NaN17.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集概況:利用NetworkX,對H企業(yè)的制造BOM進(jìn)行可視化展示:盡管只有兩個(gè)成品,整個(gè)制造網(wǎng)絡(luò)依然非常復(fù)雜,存在很多共享節(jié)點(diǎn)17.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集預(yù)處理:計(jì)算出每個(gè)節(jié)點(diǎn)的累計(jì)提前期調(diào)用計(jì)算需求上界的函數(shù)cal_demand_bound計(jì)算服務(wù)水平為0.95時(shí)的需求上界表將后續(xù)要反復(fù)使用的數(shù)據(jù)轉(zhuǎn)換成字典格式數(shù)據(jù)集預(yù)處理代碼如下:lt_dict=dict(zip(node_df['node_id'],node_df['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'})
node_df=node_df.merge(cum_lt_df,on='node_id',how='left')
print(node_df.head())17.2數(shù)據(jù)導(dǎo)入及預(yù)處理數(shù)據(jù)集預(yù)處理代碼:all_nodes=set(node_df['node_id'])
#提前期
lt_dict=dict(zip(node_df['node_id'],node_df['lt']))
#累計(jì)提前期
cum_lt_dict=dict(zip(node_df['node_id'],node_df['cum_lt']))
#單位持貨成本
hc_dict=dict(zip(node_df['node_id'],node_df['hc']))
#對客戶承諾服務(wù)時(shí)間sla
sla_dict=dict(zip(node_df['node_id'],node_df['sla']))
#每個(gè)節(jié)點(diǎn)對應(yīng)覆蓋時(shí)間的安全庫存量
ss_ct_dict={(node,time):ssfornode,time,ssin
demand_bound_df[['node_id','time','ss_qty']].values}17.3應(yīng)用分段線性函數(shù)近似算法求解近似最優(yōu)的策略
17.3應(yīng)用分段線性函數(shù)近似算法求解近似最優(yōu)的策略
17.3應(yīng)用分段線性函數(shù)近似算法求解近似最優(yōu)的策略代碼如下:defcal_ar_br(demand_bound_df):
#對時(shí)間取差
demand_bound_df['t_diff']=demand_bound_df['time'].diff()
demand_bound_df.loc[demand_bound_df['time']==
0,'t_diff']=
0
#對需求上界取差
demand_bound_df['db_diff']=demand_bound_df['demand_bound'].diff()
demand_bound_df.loc[demand_bound_df['time']==
0,'db_diff']=
0
#根據(jù)ar和br的公式,計(jì)算ar與br
demand_bound_df['ar']=demand_bound_df['db_diff']/
\
demand_bound_df['t_diff']-
\
demand_bound_df['mean']
demand_bound_df['br']=demand_bound_df['demand_bound']-
\
demand_bound_df['mean']*
\
demand_bound_df['time']-
\
demand_bound_df['ar']*demand_bound_df['time']
demand_bound_df.loc[demand_bound_df['time']==
0,'ar']=
0
demand_bound_df.loc[demand_bound_df['time']==
0,'br']=
0
#轉(zhuǎn)換成字典格式,方便后續(xù)讀取
ar_dict={(node,time):arfornode,time,ar
indemand_bound_df[['node_id','time','ar']].values}
br_dict={(node,time):brfornode,time,br
indemand_bound_df[['node_id','time','br']].values}
returnar_dict,br_dict
ar_dict,br_dict=cal_ar_br(demand_bound_df)17.3應(yīng)用分段線性函數(shù)近似算法求解近似最優(yōu)的策略代碼如下:jt_list=list(ar_dict.keys())
jt_dict={j:list(range(0,int(cum_lt_dict[j])+
1))forjinall_nodes}#生成COPT的環(huán)境
env=Envr()
#建立空的模型
m=env.createModel('pwl')CardinalOptimizerv4.0.2.BuilddateFeb232022
CopyrightCardinalOperations2022.AllRightsReserved#服務(wù)響應(yīng)時(shí)間
S=m.addVars(all_nodes,vtype=COPT.CONTINUOUS,lb=0,nameprefix='S')
#被服務(wù)時(shí)間
SI=m.addVars(all_nodes,vtype=COPT.CONTINUOUS,lb=0,nameprefix='SI')
#覆蓋時(shí)間
CT=m.addVars(all_nodes,vtype=COPT.CONTINUOUS,lb=0,nameprefix='CT')
#用來控制只選擇一段的0-1變量
U=m.addVars(jt_list,vtype=COPT.BINARY,nameprefix='U')
#用于近似覆蓋時(shí)間的變量
Z=m.addVars(jt_list,vtype=COPT.CONTINUOUS,lb=0,nameprefix='Z')17.3應(yīng)用分段線性函數(shù)近似算法求解近似最優(yōu)的策略代碼如下:m.setObjective(quicksum(
hc_dict[j]*(ar_dict[j,t]*Z[j,t]+br_dict[j,t]+U[j,t])forj,t
injt_list),COPT.MINIMIZE)m.addConstrs(
(CT[j]==quicksum(Z[j,t]fortinjt_dict[j])forjinall_nodes),
nameprefix='approx_CT')m.addConstrs(((t-
1)*U[j,t]<=Z[j,t]forj,tinjt_list),
nameprefix='time_interval_lhs')
m.addConstrs((t*U[j,t]>=Z[j,t]forj,tinjt_list),
nameprefix='time_interval_rhs')m.addConstrs((quicksum(U[j,t]fortinjt_dict[j])==
1
forj
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 個(gè)性化視頻制作委托合同書(2024年版)版B版
- 2025年環(huán)保型打印紙張品研發(fā)與認(rèn)證合同4篇
- 2025年度文化創(chuàng)意產(chǎn)業(yè)承包經(jīng)營合同賠償與創(chuàng)意成果轉(zhuǎn)化3篇
- 二零二五版房產(chǎn)維修基金管理合同3篇
- 2025年綠色建筑彩板房采購協(xié)議3篇
- 2025年度商業(yè)地產(chǎn)項(xiàng)目租賃協(xié)議范本4篇
- 二零二五年度美容師客戶滿意度調(diào)查與反饋協(xié)議4篇
- 2024年銷售合同風(fēng)險(xiǎn)評估3篇
- 2025版合伙企業(yè)個(gè)人退伙權(quán)益保障協(xié)議書3篇
- 2025年度數(shù)據(jù)中心基礎(chǔ)設(shè)施建設(shè)承包協(xié)議8篇
- 2025年度公務(wù)車輛私人使用管理與責(zé)任協(xié)議書3篇
- 售后工程師述職報(bào)告
- 綠化養(yǎng)護(hù)難點(diǎn)要點(diǎn)分析及技術(shù)措施
- 2024年河北省高考?xì)v史試卷(含答案解析)
- 車位款抵扣工程款合同
- 小學(xué)六年級數(shù)學(xué)奧數(shù)題100題附答案(完整版)
- 高中綜評項(xiàng)目活動設(shè)計(jì)范文
- 英漢互譯單詞練習(xí)打印紙
- 2023湖北武漢華中科技大學(xué)招聘實(shí)驗(yàn)技術(shù)人員24人筆試參考題庫(共500題)答案詳解版
- 一氯二氟甲烷安全技術(shù)說明書MSDS
- 物流簽收回執(zhí)單
評論
0/150
提交評論