第七章 結論與建議
第四節 研究限制與後續研究方向
國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
第四節 研究限制與後續研究方向
由於知識、能力和精力有限,而且模型是建立在一系列假設基礎之上,本研 究有許多研究限制和研究不足。
現實中,供應鏈訂購和生產的方式是多樣的,供應鏈金融的融資模式也是多 樣的,成本組成部分也是多樣的。本研究建立模型最小化成本的因素主要考慮固 定的訂購和生產成本以及原材料成本,融資模式主要是庫存融資和訂單融資(或 者應收賬款融資)。
本研究的供應鏈是兩級,現實中的供應鏈是多層級、每一層級又有許多企業 構成的複雜網絡系統,不僅層級之間具有上下游合作與決策交互影響的關係,在 同一層級之間還存在合作和競爭的關係。
本研究主要研究的是供應鏈中不易變質和價格波動性較小產品的訂貨、生產 和融資的問題,而且為單一產品。
在後續研究中可以考慮以下研究方向。
(1)供應鏈主體可以更加多元,可以涉及更多的層級和層級內有更多的企 業成員。模型只涉及零售商和製造商兩個主體,包括零售商、製造商,沒有考慮
“一對多”、“多對一”的情況,例如多個製造商和一個零售商,一個製造商多 個零售商或者多個供應商一個製造商和多個零售商等情況。
(2)可以考慮生命週期較短或者容易變質的易逝品,供應鏈具有多產品的 訂貨、生產和融資問題。
(3)考慮融資風險因素。本研究假設企業是按時還款,不存在破產的風險,
這在現實中幾乎不可能,後續研究可考慮借貸風險。
(4)製造商生產有延遲。本研究假設製造商生產沒有延遲,可放鬆這一假 設,考慮製造商生產有延遲的情況。
(5)論文模型假設供應鏈貸款沒有延期,即貸款一定可以審核通過並且馬
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
上發放,即刻可使用。可放款這一假設,考慮貸款申請有延期的情況。
(6)可以考慮價格和銷量之間的變動關係。本研究模型假設銷售價格和銷 量在各階段不變,現實中價格和銷售量是呈現一定關係的,在訂貨策略時可以考 慮價格變動的因素。
(7)考慮缺貨成本。本研究模型,有資金約束無供應鏈金融情況下,假設 不考慮缺貨成本,後續可以在模型中加入缺貨成本因素。
(8)本研究假設市場需求是確定性的,後續可放鬆這一假設,考慮需求不 確定性情況。
(9)本研究的供應鏈的總體累積利潤幾乎不變,利潤會在各成員之間分配,
後續可研究供應鏈利潤如何合理分配的問題,供應鏈合作關係與價值共創策略。
(10)本研究的二階規劃模型求解和敏感度分析結果是否與實務當中實際狀 況一致,以及分析結論對其他個案是否適用也是進一步討論的問題。
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
附錄
數值分析 Python 程式 1(有資金約束有供應鏈金融):
import numpy as np import pandas as pd
class SensitivityAnalyzer:
def __init__(self):
self.two_roles = TwoRoles() self.report = pd.DataFrame()
def solve(self, factor='financing_rate', start=0.0, stop=1.0, step=0.01, demands=None):
if demands is None:
demands = [120, 260, 90, 100]
self.report = pd.DataFrame() # 清空報告內容 if factor == 'financing_rate':
for f in np.arange(start, stop, step):
self.two_roles.solve(demands, financing_rate=f) rpt = self.two_roles.gen_report()
self.report = pd.concat([self.report, rpt]) elif factor == 'pledge_rate':
for f in np.arange(start, stop, step):
self.two_roles.solve(demands, pledge_rate=f) rpt = self.two_roles.gen_report()
self.report = pd.concat([self.report, rpt]) elif factor == 'financing_fixed':
for f in np.arange(start, stop, step):
self.two_roles.solve(demands, financing_fixed=f) rpt = self.two_roles.gen_report()
self.report = pd.concat([self.report, rpt]) return self.report
class TwoRoles:
def __init__(self):
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
self.demands = self.retailer = self.manufacturer = self.report = None def solve(self, demands=None, fc=True, # Funding constraints
financing_rate=None, pledge_rate=None, financing_fixed=None):
if demands is None:
demands = [120, 260, 90, 100]
self.demands = demands self.retailer = MultiPeriods(
fc=fc, financing_rate=financing_rate, pledge_rate=pledge_rate, financing_fixed=financing_fixed)
self.retailer.solve(self.demands) mnf_demands = [p[0] for p in
self.retailer.opt_policies[(self.retailer.num_periods, 0)]]
self.manufacturer = MultiPeriods(
retailer=False, fc=fc,
financing_rate=financing_rate, pledge_rate=pledge_rate, financing_fixed=financing_fixed)
self.manufacturer.solve(mnf_demands) def gen_report(self):
self.retailer.gen_report() self.manufacturer.gen_report()
self.report = pd.concat([self.retailer.report,
self.manufacturer.report.drop(columns=['需求(D)'])], axis=1) return self.report
class MultiPeriods:
def __init__(self, retailer=True, fc=True, # Funding constraints financing_rate=None, pledge_rate=None,
financing_fixed=None):
# 初始化單期求解器 self.lv0_idx = None if financing_rate is None:
rtl_financing_rate = 0.0075 mnf_financing_rate = 0.01 else:
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
rtl_financing_rate = financing_rate mnf_financing_rate = financing_rate self.lv0_idx = {'融資利率': financing_rate}
if pledge_rate is None:
rtl_pledge_rate = 0.8 mnf_pledge_rate = 0.7 else:
rtl_pledge_rate = pledge_rate mnf_pledge_rate = pledge_rate
self.lv0_idx = {'質押率': pledge_rate}
if financing_fixed is None:
rtl_financing_fixed = 2000.0 mnf_financing_fixed = 2000.0 else:
rtl_financing_fixed = financing_fixed mnf_financing_fixed = financing_fixed
self.lv0_idx = {'固定融資成本': financing_fixed}
self.retailer = SinglePeriod(
producing_fixed=5000.0, producing_var=799.0,
financing_fixed=rtl_financing_fixed, financing_rate=rtl_financing_rate, pledge_rate=rtl_pledge_rate, price=1399.0,
)
self.manufacture = SinglePeriod(
producing_fixed=6000.0, producing_var=486.0, capacity=400,
financing_fixed=mnf_financing_fixed, financing_rate=mnf_financing_rate, pledge_rate=mnf_pledge_rate, price=799.0,
role_name='製造商',
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
)
self.role = self.retailer if retailer else self.manufacture """初始化若干集合:
- self.opt_states, 最優狀態集合, 資料類型是字典:
- key 為元組(期次, 期末庫存);
- value 為元組(期末現金, 最小累計成本).
- self.opt_policies, 最優策略集合, 資料類型為字典:
- key 為元組(期次, 期末庫存);
- value 為一個清單, 內容元素為元組(訂購數量, 期末庫存, 融 資數量, 期末資金, 當期成本, 累計成本).
- self.utilities, 決策集合, 資料類型為清單, 內容元素為元組 (上期期末庫存, 上期期末現金, 當期訂購(生產)數量, 當期融 資數量, 當期成本).
- self.cum_costs, 累計成本集合, 資料類型為清單.
"""
initial_capital = 60000.0 if fc else float('inf') # 初始現金
self.opt_states = {(0, 0): (initial_capital, 0.0)} # 最優狀態集合初始值 self.dft_state = (0.0, float('inf')) # 最優狀態集合中所不包含狀態的預設 返回值: 期末現金 0.0, 最小累計成本無窮大
self.opt_policies = {}
self.utilities = []
self.cum_costs = []
# 初始化一些變數為空值.
self.demands = self.num_periods = self.report = None def solve(self, demands=None, ):
if demands is None:
demands = [120, 260, 90, 100]
self.num_periods = len(demands)
self.demands = [0] + demands + [0] # 列表前後補 0, 避免索引時下標 溢出.
n = self.num_periods + 1 # 不直接用 self.num_periods 作為迴圈參數, 因為迴圈中會修改它.
for k in range(1, n):
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
self.role.demand = self.demands[k]
for inv in range(self.upper_inv(k) + 1):
self.role.inventory = inv # 當期期末庫存 self.utilities = [] # 清空決策集合
self.cum_costs = [] # 清空累計成本集合 # 遍歷可能的上期期末庫存
for pre_inv in range(self.upper_inv(k - 1) + 1):
self.role.pre_inventory = pre_inv # 上期期末庫存 self.role.pre_capital = self.opt_states.get((k - 1, pre_inv), self.dft_state)[0] # 上期期末資金
self.role.cal_producing_volume() # 計算訂購數量 self.role.cal_financing_volume() # 計算融資數量 self.role.cal_cost() # 計算當期成本
# 追加內容至決策集合 self.utilities.append(
(self.role.pre_inventory, self.role.pre_capital,
self.role.producing_volume, self.role.financing_volume, self.role.cost)
)
if self.role.financing_possible():
# 如果以上條件通過, 有兩種可能: 一是融資數量不 超過質押數量, 二是不需要融資.
cum_cost = self.opt_states.get((k - 1, pre_inv), self.dft_state)[1] + self.role.cost
self.cum_costs.append(cum_cost) else:
self.cum_costs.append(float('inf')) opt_cum_cost = min(self.cum_costs)
if opt_cum_cost != float('inf'):
idx = self.cum_costs.index(opt_cum_cost)
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
self.role.pre_capital,
self.role.producing_volume, self.role.financing_volume, self.role.cost) = self.utilities[idx]
self.role.cal_capital()
self.opt_states[(k, self.role.inventory)] = (self.role.capital, opt_cum_cost)
self.opt_policies[(k, self.role.inventory)] = \
self.opt_policies.get((k - 1, self.role.pre_inventory), []) + [
(self.role.producing_volume, self.role.inventory,
self.role.financing_volume, self.role.capital,
self.role.cost, opt_cum_cost) ]
if sum(1 for (p, inv) in self.opt_states.keys() if p == k) == 0:
p_i_set = list(self.opt_states.keys()) for (p, i) in p_i_set:
if p == (k - 1):
# 更新最優狀態集合: (期末現金, 最小累計成本) self.opt_states[(k, i)] = self.opt_states[(p, i)]
if k == 1:
cap = self.opt_states[(0, 0)][0]
self.opt_policies[(k, 0)] = [(0, 0, 0.0, cap, 0.0, 0.0)]
else:
"""更新最優策略集合:
(訂購數量, 期末庫存, 融資數量, 期末資金, 當 期成本, 累計成本)
"""
cap = self.opt_policies[(p, i)][-1][-3]
cur = self.opt_policies[(p, i)][-1][-2]
cum = self.opt_policies[(p, i)][-1][-1]
self.opt_policies[(k, i)] = self.opt_policies[(p, i)] + [(0, i, 0.0, cap, cur, cum)]
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
def upper_inv(self, k, capacity=float('inf')):
# 計算可能的期末庫存上限
return min(sum(self.demands[k + 1:]), capacity * k) def gen_report(self):
state = (self.num_periods, 0) # 初始化報告
if self.lv0_idx is None:
idx = pd.Index(range(state[0] + 1), name='期次(Period)')
self.report = pd.DataFrame(self.demands[:state[0] + 1], index=idx, columns=['需求(D)'])
else:
name, value = list(self.lv0_idx.items())[0]
idx = pd.MultiIndex.from_product([[value], range(state[0] + 1)], names=[name, '期次(Period)'])
self.report = pd.DataFrame(self.demands[:state[0] + 1], index=idx, columns=['需求(D)'])
idx = idx[1:]
m = self.role.role_mark
v = '訂購' if self.role.role_name == '零售商' else '生產' q = 'q' if self.role.role_name == '零售商' else 'Q'
cols = [f'{v}數量({q + m})', f'期末庫存(I{m})', f'融資數量(F{m})', f'期末 現金(Y{m})', f'當期成本(C{m})', '累計成本']
cols = [self.role.role_name + col for col in cols]
df = pd.DataFrame.from_records(self.opt_policies[state], index=idx, columns=cols)
self.report = pd.concat([self.report, df], axis=1) if self.lv0_idx is None:
self.report.loc[0, self.role.role_name + f'期末庫存(I{m})'] = 0 self.report.loc[0, self.role.role_name + f'期末現金(Y{m})'] = self.opt_states[(0, 0)][0]
self.report.rename_axis('期次(Period)', inplace=True) else:
name, value = list(self.lv0_idx.items())[0]
self.report.loc[(value, 0), self.role.role_name + f'期末庫存(I{m})'] = 0
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
self.report.loc[(value, 0), self.role.role_name + f'期末現金(Y{m})'] = self.opt_states[(0, 0)][0]
self.report.rename_axis([name, '期次(Period)'], inplace=True) return self.report
class SinglePeriod:
def __init__(self, producing_fixed, producing_var, financing_fixed, financing_rate, pledge_rate, price,
capacity=float('inf'), demand=0, pre_inventory=0, inventory=0, pre_capital=0,
role_name='零售商', role_mark='r'):
# 設定值
self.producing_fixed = producing_fixed self.producing_var = producing_var self.unit_holding = 50.0
self.financing_fixed = financing_fixed self.financing_rate = financing_rate self.price = price
self.capacity = capacity self.pledge_rate = pledge_rate self.demand = demand
self.pre_inventory = pre_inventory self.inventory = inventory
self.pre_capital = pre_capital self.role_name = role_name self.role_mark = role_mark # 初始化需要求解的值 self.producing_volume = 0 self.financing_volume = None self.cost = 0.0
self.producing_cost = 0.0 self.holding_cost = 0.0 self.financing_cost = 0.0
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
self.capital = 0 # self.profit = 0
def cal_producing_volume(self):
# 計算生產數量
self.producing_volume = max(0, self.inventory + self.demand - self.pre_inventory)
return self.producing_volume def cal_financing_volume(self):
self.cal_producing_cost() self.cal_holding_cost()
if self.pre_capital >= self.producing_cost + self.holding_cost: # 判斷上 期期末資金是否足夠支付生產(訂購)和存儲成本
self.financing_volume = 0.0 else:
numerator = self.producing_cost + self.holding_cost + self.financing_fixed - self.pre_capital
denominator = 1 - self.financing_rate
self.financing_volume = numerator / denominator return self.financing_volume
# def cal_profit(self):
# return self.profit def cal_cost(self):
if self.financing_volume is None:
self.cal_financing_volume() self.cal_financing_cost()
self.cost = self.producing_cost + self.holding_cost + self.financing_cost return self.cost
def cal_producing_cost(self):
self.producing_cost = self.producing_fixed * ita(self.producing_volume) + \ self.producing_var * self.producing_volume return self.producing_cost
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
def cal_holding_cost(self):
self.holding_cost = self.unit_holding * self.inventory return self.holding_cost
def cal_financing_cost(self):
self.financing_cost = self.financing_fixed * ita(self.financing_volume) + \ self.financing_volume * self.financing_rate return self.financing_cost
def cal_capital(self):
self.capital = self.pre_capital + self.price * self.producing_volume - self.cost
return self.capital
def financing_possible(self): # 判斷融資金額是否超過質押上限 return self.financing_volume <= self.pledge_rate * self.price * (self.pre_inventory + self.producing_volume)
def ita(x):
return 1 if x > 0 else 0
if __name__ == '__main__':