《現(xiàn)代庫存管理:模型、算法與Python實(shí)現(xiàn)》 課件 第16、17章 某食品企業(yè)Z的分銷網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)、某家電企業(yè)H的制造網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)_第1頁
《現(xiàn)代庫存管理:模型、算法與Python實(shí)現(xiàn)》 課件 第16、17章 某食品企業(yè)Z的分銷網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)、某家電企業(yè)H的制造網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)_第2頁
《現(xiàn)代庫存管理:模型、算法與Python實(shí)現(xiàn)》 課件 第16、17章 某食品企業(yè)Z的分銷網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)、某家電企業(yè)H的制造網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)_第3頁
《現(xiàn)代庫存管理:模型、算法與Python實(shí)現(xiàn)》 課件 第16、17章 某食品企業(yè)Z的分銷網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)、某家電企業(yè)H的制造網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)_第4頁
《現(xiàn)代庫存管理:模型、算法與Python實(shí)現(xiàn)》 課件 第16、17章 某食品企業(yè)Z的分銷網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)、某家電企業(yè)H的制造網(wǎng)絡(luò)庫存優(yōu)化實(shí)戰(zhàn)_第5頁
已閱讀5頁,還剩42頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論