본문 바로가기
Analysis/Example

물류 네트워크 설계 - 최적화 라이브러리

by 5ole 2021. 2. 15.

1. 전제조건 

 

  • 제품 판매하는 대리점 P, Q
  • 판매되는 상품 A, B
  • 상품 일정 수요 예측해 공장 X, Y 에서 생산
  • 제품마다, 공장마다 다른 생산라인 레인 0, 1
  • 공장에서 대리점까지 운송비, 제고 비용 등 고려해 생산 방법 결정 

 

2. 데이터 정보

 

  • trans_cost.csv
  • demand.csv
  • supply.csv
  • trans_route_pos.csv
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

import networkx as nx
from itertools import product
from pulp import LpVariable, lpSum, value 
from ortoolpy import model_min, addvars, addvals

os.chdir('C:\\Users\\leeso\\Downloads\\pyda100-master\\7장')


df_tc = pd.read_csv('trans_cost.csv', index_col="공장")
df_demand = pd.read_csv('demand.csv')
df_supply = pd.read_csv('supply.csv')
df_pos = pd.read_csv('trans_route_pos.csv')

 

 

3. 운송 최적화 문제

 

  • 아래 글과 최적화 성능 비교

2021/02/15 - [Data/Data Analysis] - 물류 경로 최적화 - 네트워크 가시화

 

물류 경로 최적화 - 네트워크 가시화

1. 전제조건 제품의 부품을 보관하는 창고에서 공장까지 운송 비용을 낮추기 어떤 창고에서 어떤 공장으로 어느 정도의 양을 운송할 지 검토 2. 데이터 정보 trans_route.csv : 운송 정보 - 공장에서

5ohyun.tistory.com

 

(1) 라이브러리를 사용해 최적화 모델 작성

 

  • pulp 라이브러리를 사용해 최적화 모델 작성
  • ortoolpy 라이브러리를 사용해 목적함수 생성
np.random.seed(1)
nw = len(df_tc.index) # W1, W2, W3
nf = len(df_tc.columns) # F1, F2, F3, F4
pr = list(product(range(nw), range(nf))) #12개


m1 = model_min() # 최소화 실행할 모델 정의

v1 = {(i,j):LpVariable('v%d_%d'%(i,j),lowBound=0) for i,j in pr} # 주요 변수

m1 += lpSum(df_tc.iloc[i][j]*v1[i,j] for i,j in pr) # 각 요소의 곱의 합으로 함수 정의


# 제약조건

for i in range(nw):
    m1 += lpSum(v1[i,j] for j in range(nf)) <= df_supply.iloc[0][i] # 공급량 이내로 생산 가능
    
for j in range(nf):
    m1 += lpSum(v1[i,j] for i in range(nw)) >= df_demand.iloc[0][j] # 수요량 이상으로 있어야
    
m1.solve() # 1 출력

 

(2) 총 운송 비용 계산

 

  • 총 운송 비용 1296만원으로 위의 글과 비교했을 때 (1433만원) 크게 비용이 절감됨
df_tr_sol = df_tc.copy()

total_cost = 0

for k,x in v1.items():
    i,j = k[0],k[1] # (2,3)
    df_tr_sol.iloc[i][j] = value(x) # 20
    total_cost += df_tc.iloc[i][j]*value(x)
    
print(df_tr_sol)

print("총 운송 비용:"+str(total_cost))

 

4. 최적화 결과 확인

 

(1) 네트워크 가시화

 

  • chap6에서 사용했던 NetworkX 사용해 네트워크 가시화
  • 운송경로가 집중적으로 되어있음
# 데이터 불러오기
df_tr = df_tr_sol.copy() # 최적화 결과

# 객체 생성
G = nx.Graph()

# 노드 설정
for i in range(len(df_pos.columns)):
    G.add_node(df_pos.columns[i])

# 엣지 설정 & 엣지의 가중치 리스트화
num_pre = 0
edge_weights = []
size = 0.1
for i in range(len(df_pos.columns)):
    for j in range(len(df_pos.columns)):
        if not (i==j):
            # 엣지 추가
            G.add_edge(df_pos.columns[i],df_pos.columns[j])
            # 엣지 가중치 추가
            if num_pre<len(G.edges):
                num_pre = len(G.edges)
                weight = 0
                if (df_pos.columns[i] in df_tr.columns)and(df_pos.columns[j] in df_tr.index):
                    if df_tr[df_pos.columns[i]][df_pos.columns[j]]:
                        weight = df_tr[df_pos.columns[i]][df_pos.columns[j]]*size
                elif(df_pos.columns[j] in df_tr.columns)and(df_pos.columns[i] in df_tr.index):
                    if df_tr[df_pos.columns[j]][df_pos.columns[i]]:
                        weight = df_tr[df_pos.columns[j]][df_pos.columns[i]]*size
                edge_weights.append(weight)
                

# 좌표 설정
pos = {}
for i in range(len(df_pos.columns)):
    node = df_pos.columns[i]
    pos[node] = (df_pos[node][0],df_pos[node][1])
    
# 그리기
nx.draw(G, pos, with_labels=True,font_size=16, node_size = 1000, node_color='k', font_color='w', width=edge_weights)
plt.show()

 

 

(2) 제약 조건 확인

 

  • 1로 모두 만족하고 있음을 볼 수 있다.
# 수요측
def condition_demand(df_tr,df_demand):
    flag = np.zeros(len(df_demand.columns))
    for i in range(len(df_demand.columns)):
        temp_sum = sum(df_tr[df_demand.columns[i]])
        if (temp_sum>=df_demand.iloc[0][i]):
            flag[i] = 1
    return flag
            
# 공급측
def condition_supply(df_tr,df_supply):
    flag = np.zeros(len(df_supply.columns))
    for i in range(len(df_supply.columns)):
        temp_sum = sum(df_tr.loc[df_supply.columns[i]])
        if temp_sum<=df_supply.iloc[0][i]:
            flag[i] = 1
    return flag

print("수요 조건 계산 결과:"+str(condition_demand(df_tr_sol,df_demand)))
print("공급 조건 계산 결과:"+str(condition_supply(df_tr_sol,df_supply)))

 

 

+ 참고 자료 및 출처

 

댓글