network-design について
サプライチェーンの企画・運営担当者向けのネットワーク設計スキルです。最適化モデルやシナリオ分析を用いて、施設配置、物流、コストとサービス水準の両立を検討します。
主な機能
- 01施設配置と容量制約の最適化
- 02多段階・ハイブリッドネットワーク案
- 03コストとサービス水準の比較
- 04需要・輸送費の感度分析
- 05段階的な導入計画
活用シーン
- 01集中型と地域分散型の比較
- 02配送センターの新設・再設計の評価
- 03需要増加が施設配置に与える影響の検討
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill network-designインストール後、Claude Code で/network-designを入力して読み込まれたか確認します。
詳細
ネットワーク設計
サプライチェーンネットワークの設計と最適化に精通しています。施設コスト、輸送コスト、在庫コスト、サービスレベルのバランスを取りながら、コスト効率とサービス効率に優れたサプライチェーンネットワークを設計することを目指します。
初期評価
ネットワークを設計する前に、以下を把握します。
-
ビジネスの背景
- 地理的な対象範囲はどこですか?(地域、国内、グローバル)
- この分析を行う目的は何ですか?(成長、統合、コスト削減)
- 現在のネットワーク構成はどうなっていますか?(DC、工場、拠点の数)
- グリーンフィールド(新規ネットワーク)ですか、それともブラウンフィールド(既存ネットワークの最適化)ですか?
-
戦略目標
- 主な目標は何ですか?(コスト最小化、サービス最大化、または両方)
- サービスレベルの目標値はありますか?(配送時間、充足率)
- 予算上の制約や投資上限はありますか?
- 実施までのスケジュールはどうなっていますか?
-
データの利用可否
- 拠点別の顧客需要はありますか?
- 現在の施設コストと処理能力のデータはありますか?
- 輸送料金と距離のデータはありますか?
- 製品特性(容積、重量、価値)は把握していますか?
- 着地コスト、関税、税金のデータはありますか?
-
制約
- 維持しなければならない既存施設はありますか?
- 労働組合や労働協約に関する制約はありますか?
- 顧客固有の要件はありますか?
- 規制やコンプライアンス上の要件はありますか?
ネットワーク設計フレームワーク
戦略的なネットワークの意思決定
1. エシェロン数
- 単一エシェロン:工場 → 顧客(直送)
- 2エシェロン:工場 → DC → 顧客
- 3エシェロン:工場 → RDC → 地域DC → 顧客
- ハイブリッド:直送とDC経由のフルフィルメントを組み合わせる
2. 施設の種類
- 製造工場:生産拠点
- 配送センター(DC):大規模な地域施設
- クロスドック:保管を最小限に抑えた通過型施設
- 前方在庫拠点:地域内の在庫拠点
- 3PL施設:倉庫業務を外部委託する施設
3. フロー戦略
- 見込み生産:在庫を構築し、DCから出荷する
- 受注生産:工場から直送する
- 受注構成:DCで最終組み立てを行う
- ドロップシップ:サプライヤーから顧客へ直送する
ネットワーク最適化モデル
施設立地問題の種類
容量制約なし施設立地問題(UFL)
- 施設に容量制限がない
- 最小化するもの:固定費 + 輸送コスト
- より単純で、コストの上限値を算出できる
容量制約付き施設立地問題(CFL)
- 施設に処理能力や保管容量の制限がある
- より現実的で、より多くの施設が必要になる場合がある
- 解くのがより難しい
P-メディアン問題
- P個の施設を配置する
- 顧客までの加重距離を最小化する
- サービス重視
P-センター問題
- P個の施設を配置する
- 任意の顧客までの最大距離を最小化する
- 緊急サービス、カバレッジ
ハブ立地問題
- ハブ・アンド・スポーク型ネットワーク
- ハブを経由してフローを集約する
- 輸送における規模の経済
数理最適化のアプローチ
混合整数計画(MIP)モデル
決定変数:
Binary variables:
y_j = 1 if facility j is opened, 0 otherwise
Continuous variables:
x_ij = flow from facility j to customer i (units)
目的関数:
Minimize:
Σ_j (f_j * y_j) # Fixed facility costs
+ Σ_i Σ_j (c_ij * x_ij) # Transportation costs
+ Σ_j (v_j * Σ_i x_ij) # Variable handling costs
+ Σ_j (h_j * Inventory_j) # Inventory carrying costs
制約条件:
1. Demand satisfaction:
Σ_j x_ij >= d_i ∀ customers i
2. Capacity constraints:
Σ_i x_ij <= Cap_j * y_j ∀ facilities j
3. Facility activation:
x_ij <= d_i * y_j ∀ i, j
4. Non-negativity:
x_ij >= 0, y_j ∈ {0,1}
Pythonによる実装(PuLP)
from pulp import *
import pandas as pd
import numpy as np
def optimize_network(customers, facilities, demand, costs):
"""
Network design optimization using MIP
Parameters:
- customers: list of customer locations
- facilities: list of potential DC locations
- demand: dict {customer: demand_volume}
- costs: dict with 'fixed', 'transport', 'handling'
"""
# Create problem
prob = LpProblem("Network_Design", LpMinimize)
# Decision variables
# y[j] = 1 if facility j is opened
y = LpVariable.dicts("Facility",
facilities,
cat='Binary')
# x[i,j] = flow from facility j to customer i
x = LpVariable.dicts("Flow",
[(i,j) for i in customers for j in facilities],
lowBound=0,
cat='Continuous')
# Objective function
prob += (
# Fixed facility costs
lpSum([costs['fixed'][j] * y[j] for j in facilities]) +
# Transportation costs
lpSum([costs['transport'][i,j] * x[i,j]
for i in customers for j in facilities]) +
# Variable handling costs
lpSum([costs['handling'][j] * x[i,j]
for i in customers for j in facilities])
)
# Constraints
# 1. Each customer's demand must be satisfied
for i in customers:
prob += lpSum([x[i,j] for j in facilities]) >= demand[i], \
f"Demand_{i}"
# 2. Facility capacity constraints
for j in facilities:
prob += lpSum([x[i,j] for i in customers]) <= \
costs['capacity'][j] * y[j], \
f"Capacity_{j}"
# 3. Can only ship from open facilities
for i in customers:
for j in facilities:
prob += x[i,j] <= demand[i] * y[j], \
f"Open_{i}_{j}"
# Solve
prob.solve(PULP_CBC_CMD(msg=1))
# Extract results
results = {
'status': LpStatus[prob.status],
'total_cost': value(prob.objective),
'open_facilities': [j for j in facilities if y[j].varValue > 0.5],
'flows': {(i,j): x[i,j].varValue
for i in customers
for j in facilities
if x[i,j].varValue > 0.01}
}
return results
# Example usage
customers = ['Customer_A', 'Customer_B', 'Customer_C']
facilities = ['DC_1', 'DC_2', 'DC_3']
demand = {
'Customer_A': 1000,
'Customer_B': 1500,
'Customer_C': 800
}
costs = {
'fixed': {
'DC_1': 500000,
'DC_2': 600000,
'DC_3': 450000
},
'capacity': {
'DC_1': 3000,
'DC_2': 2500,
'DC_3': 2000
},
'transport': {
('Customer_A', 'DC_1'): 5.0,
('Customer_A', 'DC_2'): 8.0,
# ... (distance-based rates)
},
'handling': {
'DC_1': 2.0,
'DC_2': 2.5,
'DC_3': 1.8
}
}
result = optimize_network(customers, facilities, demand, costs)
print(f"Optimal cost: ${result['total_cost']:,.0f}")
print(f"Open facilities: {result['open_facilities']}")
コスト要素
1. 施設の固定費
不動産:
- 賃料($/平方フィート/年)
- 固定資産税
- 建物の減価償却費
- 保険
人件費:
- 倉庫スタッフ(基本給 + 福利厚生)
- 管理職
- 事務サポート
設備:
- マテリアルハンドリング機器
- ラックと棚
- ITシステム(WMSなど)
- 光熱費(電気、HVAC)
一般的な範囲:
- 小規模DC(50K平方フィート):年間$500K~$1M
- 中規模DC(200K平方フィート):年間$2M~$4M
- 大規模DC(500K平方フィート以上):年間$5M~$10M以上
2. 輸送コスト
トラック積載(TL):
- マイル単価(レーンや燃料によって変動)
- 一般的な料金:積載時で1マイルあたり$2.00~$3.50
- 付帯料金(待機料、荷役料など)
トラック未満積載(LTL):
- Cwt(100ポンドあたり)の料金
- 距離 + 貨物クラス
- 一般的な料金:距離に応じてCwtあたり$15~$50
小包:
- ゾーン別料金(UPS、FedEx)
- 容積重量による料金設定
- 住宅向け追加料金
モデリングのアプローチ:
# Distance-based transportation cost
def transport_cost(distance_miles, weight_lbs, mode='TL'):
"""Calculate transportation cost"""
if mode == 'TL':
# Full truckload
if weight_lbs >= 40000: # Full truck
return distance_miles * 2.50
else:
# LTL or partial
return distance_miles * 3.00
elif mode == 'LTL':
# Less than truckload
cwt = weight_lbs / 100
# Distance brackets
if distance_miles < 500:
rate = 20
elif distance_miles < 1000:
rate = 35
else:
rate = 50
return cwt * rate
elif mode == 'Parcel':
# Simplified zone-based
zones = [150, 300, 600, 1000, 1400, 1800]
rates = [8, 12, 18, 25, 35, 45]
for i, zone_dist in enumerate(zones):
if distance_miles < zone_dist:
return rates[i]
return rates[-1]
3. 在庫コスト
ネットワークが在庫に与える影響:
- DC が増えるほど、安全在庫が増加します(平方根則)
- リードタイムが長くなるほど、パイプライン在庫が増加します
- 集約化すると、総在庫が減少します
平方根則:
Total_Safety_Stock = Current_SS * sqrt(N_new / N_current)
ここで、N = 在庫を保管する拠点の数
def safety_stock_network(current_ss, current_dcs, new_dcs):
"""Estimate safety stock change from network redesign"""
factor = (new_dcs / current_dcs) ** 0.5
return current_ss * factor
# Example: consolidate 5 DCs into 2
current_inventory = 1000000 # units
new_inventory = safety_stock_network(
current_inventory,
current_dcs=5,
new_dcs=2
)
print(f"Inventory reduction: {current_inventory - new_inventory:,.0f} units")
# Output: ~367,544 unit reduction
在庫保有コスト:
- 一般的に、年間で在庫価値の 20〜30%
- 内訳:資本コスト、保管、陳腐化、損傷
4. サービスレベル指標
配送時間:
- 1 日配送のサービス圏
- 2 日配送のサービス範囲
- X マイル以内の顧客の割合
充足率:
- 在庫ありでの提供可能率
- 注文の完全性
トレードオフ分析:
def service_level_analysis(dc_locations, customer_locations):
"""Analyze service coverage from network"""
service_levels = {}
for dc in dc_locations:
# Calculate distances to all customers
distances = [
haversine_distance(dc, customer)
for customer in customer_locations
]
# Service zones (miles → days)
one_day = sum(1 for d in distances if d < 250)
two_day = sum(1 for d in distances if d < 600)
service_levels[dc] = {
'1-day_%': one_day / len(customer_locations) * 100,
'2-day_%': two_day / len(customer_locations) * 100
}
return service_levels
ネットワーク設計プロセス
フェーズ 1:データ収集と検証
顧客データ:
- 配送先住所(ジオコーディング済み)
- 地点別の需要(年間、月間)
- 注文頻度と注文サイズ
- サービス要件
施設データ:
- 現在の所在地と容量
- 運用コスト
- リース条件と柔軟性
- 稼働率
製品データ:
- SKU の構成と数量
- 容積と重量
- 在庫価値
- 特別な取り扱い要件
輸送データ:
- レーン別の現在の貨物輸送費
- 料金体系
- 輸送時間
- 運送業者のサービス提供範囲
フェーズ 2:ネットワーク戦略の定義
評価する戦略オプション:
-
集約化
- 少数の大規模 DC(1〜3)
- 固定費と在庫コストの低減
- 輸送コストの増加
- 配送時間の長期化
-
分散化
- 多数の地域 DC(5〜10 以上)
- 固定費と在庫コストの増加
- 輸送コストの低減
- 配送時間の短縮
-
ハイブリッド
- 回転の遅い商品向けの全国/地域 DC
- 回転の速い商品向けの地域別前方在庫
- コストとサービスのバランス
-
直送
- 工場から顧客に直接配送
- DC コストを排除
- 輸送コストの増加(積載の集約が少ないため)
- リードタイムの長期化
フェーズ 3:シナリオモデリング
基本シナリオ:
- 現状:現在のネットワークパフォーマンス
- 現行ネットワークの最適化:既存のネットワークを改善
- グリーンフィールド:ゼロから最適なネットワークを設計
- 成長:3〜5 年後の需要に対応するネットワーク
感度分析:
- 需要の増加(±20%)
- 燃料費の変動(±30%)
- 人件費のインフレ
- サービスレベル要件
- 施設コストの変動
フェーズ 4:最適化とトレードオフ分析
最適化モデルの実行:
# Multi-scenario optimization
scenarios = {
'Cost_Min': {'weight_cost': 1.0, 'weight_service': 0.0},
'Service_Max': {'weight_cost': 0.0, 'weight_service': 1.0},
'Balanced': {'weight_cost': 0.6, 'weight_service': 0.4}
}
results = {}
for name, weights in scenarios.items():
result = optimize_network_weighted(
customers, facilities, demand, costs,
alpha=weights['weight_cost'],
beta=weights['weight_service']
)
results[name] = result
# Compare scenarios
comparison_df = pd.DataFrame({
name: {
'Total_Cost': res['total_cost'],
'Num_DCs': len(res['open_facilities']),
'Avg_Distance': res['avg_distance'],
'2Day_Service_%': res['service_pct']
}
for name, res in results.items()
}).T
パレートフロンティア:
- コストとサービスのトレードオフをプロット
- 劣るソリューションを特定
- 選択肢の範囲を提示
フェーズ 5:推奨事項と導入計画
最終的な推奨事項:
- 選択したネットワーク構成
- 段階的な導入計画
- 必要な投資
- 期待される投資回収期間
- リスク軽減策
ツールと手法
最適化ソフトウェア
商用:
- LLamasoft (Coupa):Supply Chain Guru
- Llamasoft Design:ネットワーク設計プラットフォーム
- Blue Yonder:ネットワーク最適化
- Optilogic:Cosmic Frog(クラウドベース)
- FICO Xpress:最適化スイート
- Gurobi:数理ソルバー
- CPLEX (IBM):MIP ソルバー
オープンソース:
- PuLP:Python 線形計画法
- Pyomo:Python 最適化モデリング
- OR-Tools (Google):制約最適化
- JuMP (Julia):数理最適化
Python によるネットワーク設計
# Complete network design example
import pulp
import pandas as pd
import numpy as np
from scipy.spatial.distance import cdist
class NetworkDesigner:
"""Supply chain network design optimizer"""
def __init__(self, customers_df, facilities_df):
"""
Initialize with customer and facility data
customers_df: columns = ['id', 'lat', 'lon', 'demand']
facilities_df: columns = ['id', 'lat', 'lon', 'fixed_cost', 'capacity']
"""
self.customers = customers_df
self.facilities = facilities_df
# Calculate distance matrix
self.distances = self._calculate_distances()
def _calculate_distances(self):
"""Calculate great-circle distances"""
cust_coords = self.customers[['lat', 'lon']].values
fac_coords = self.facilities[['lat', 'lon']].values
# Haversine distance in miles
distances = cdist(cust_coords, fac_coords, metric='euclidean')
distances *= 69 # Approx miles per degree
return distances
def optimize(self,
transport_rate=2.5,
handling_rate=1.0,
service_distance=None):
"""
Optimize network design
transport_rate: $/mile
handling_rate: $/unit
service_distance: max miles for service constraint
"""
prob = pulp.LpProblem("Network", pulp.LpMinimize)
# Variables
I = range(len(self.customers))
J = range(len(self.facilities))
y = pulp.LpVariable.dicts("Open", J, cat='Binary')
x = pulp.LpVariable.dicts("Flow",
[(i,j) for i in I for j in J],
lowBound=0)
# Objective
prob += (
# Fixed costs
pulp.lpSum([self.facilities.iloc[j]['fixed_cost'] * y[j]
for j in J]) +
# Transportation
pulp.lpSum([self.distances[i,j] * transport_rate * x[i,j]
for i in I for j in J]) +
# Handling
pulp.lpSum([handling_rate * x[i,j]
for i in I for j in J])
)
# Constraints
for i in I:
# Demand satisfaction
prob += pulp.lpSum([x[i,j] for j in J]) >= \
self.customers.iloc[i]['demand']
# Service distance constraint
if service_distance:
for j in J:
if self.distances[i,j] > service_distance:
prob += x[i,j] == 0
for j in J:
# Capacity
prob += pulp.lpSum([x[i,j] for i in I]) <= \
self.facilities.iloc[j]['capacity'] * y[j]
# Solve
prob.solve(pulp.PULP_CBC_CMD(msg=0))
# Results
return self._extract_results(prob, y, x, I, J)
def _extract_results(self, prob, y, x, I, J):
"""Extract and format results"""
open_dcs = [self.facilities.iloc[j]['id']
for j in J
if y[j].varValue > 0.5]
flows = []
for i in I:
for j in J:
if x[i,j].varValue > 0.01:
flows.append({
'customer': self.customers.iloc[i]['id'],
'facility': self.facilities.iloc[j]['id'],
'flow': x[i,j].varValue,
'distance': self.distances[i,j]
})
flows_df = pd.DataFrame(flows)
return {
'status': pulp.LpStatus[prob.status],
'total_cost': pulp.value(prob.objective),
'open_facilities': open_dcs,
'num_facilities': len(open_dcs),
'flows': flows_df,
'avg_distance': flows_df['distance'].mean(),
'max_distance': flows_df['distance'].max()
}
# Example usage
customers = pd.DataFrame({
'id': ['C1', 'C2', 'C3', 'C4'],
'lat': [34.05, 41.88, 39.74, 29.76],
'lon': [-118.24, -87.63, -104.99, -95.37],
'demand': [1000, 1500, 800, 1200]
})
facilities = pd.DataFrame({
'id': ['DC_West', 'DC_Central', 'DC_East'],
'lat': [36.17, 39.10, 40.71],
'lon': [-115.14, -94.58, -74.01],
'fixed_cost': [500000, 450000, 600000],
'capacity': [4000, 3500, 3000]
})
designer = NetworkDesigner(customers, facilities)
result = designer.optimize(transport_rate=2.5, handling_rate=1.0)
print(f"Total Cost: ${result['total_cost']:,.0f}")
print(f"Open DCs: {result['open_facilities']}")
print(f"Avg Distance: {result['avg_distance']:.1f} miles")
高度なトピック
複数期間のネットワーク設計
考慮事項:
- 時間の経過に伴う需要の増加
- 施設の段階的な開設/閉鎖
- 能力拡張の選択肢
- 投資時期
# Multi-period formulation (simplified)
T = range(planning_horizon) # periods
# Variables
y = {} # y[j,t] = facility j opened in period t
z = {} # z[j,t] = facility j operating in period t
for t in T:
for j in J:
y[j,t] = pulp.LpVariable(f"Open_{j}_{t}", cat='Binary')
z[j,t] = pulp.LpVariable(f"Operating_{j}_{t}", cat='Binary')
# Constraint: once opened, stays open
for t in range(1, len(T)):
for j in J:
prob += z[j,t] >= z[j,t-1]
グローバルネットワーク設計
追加の考慮事項:
- 関税と諸税
- 通関所要時間
- 為替レート
- 移転価格
- 税務最適化
- 自由貿易地域
着地コストの計算:
def landed_cost(product_cost, transport, duty_rate, tax_rate):
"""Calculate total landed cost"""
customs_value = product_cost + transport
duty = customs_value * duty_rate
taxable_value = customs_value + duty
tax = taxable_value * tax_rate
total = product_cost + transport + duty + tax
return total
確率的ネットワーク設計
不確実性の要因:
- 需要(シナリオ)
- コスト(燃料費、人件費)
- 為替レート
- 混乱のリスク
二段階確率計画法:
- 第 1 段階:施設立地の決定(不確実性が顕在化する前)
- 第 2 段階:フローの決定(シナリオが明らかになった後)
よくある課題と解決策
課題:データ品質
問題:
- 顧客の所在地が不正確です
- 需要データが不完全です
- コスト情報が不足しています
解決策:
- 住所をジオコーディングします(Google Maps API など)
- 小規模な顧客を郵便番号単位にまとめます
- 不足しているコストには業界ベンチマークを使用します
- 不確実な入力値に対して感度分析を行います
課題:候補地が多すぎる
問題:
- 組み合わせが爆発的に増加します(候補地が1,000か所以上)
解決策:
- 重力モデルを使って有力な候補に絞り込みます
- クラスタリングアルゴリズムを使用します
- 2段階のアプローチを採用します。まず戦略レベルで検討し、その後詳細に検討します
- 一部の施設を固定します(既存施設、維持必須の施設)
課題:複数製品の複雑さ
問題:
- 製品ごとに要件が異なります
- 冷蔵品と常温品、危険物などがあります
解決策:
- 製品ファミリー単位にまとめます
- マルチコモディティフローモデルを使用します
- 製品タイプごとにネットワークを分けます
- 共有施設と専用施設を検討します
課題:需要の変動
問題:
- 需要は時間とともに変化します
- 季節性や成長があります
解決策:
- 容量の算定にはピーク需要を使用します
- 複数期間モデルを使用します
- 柔軟な施設(拡張可能)を採用します
- シナリオ計画を行います(成長ケース)
出力形式
ネットワーク設計レポート
エグゼクティブサマリー:
- 推奨するネットワーク構成
- 総コストと現状に対する削減額
- サービスレベルの改善
- 導入スケジュールと投資額
ネットワーク構成:
| 施設 | 所在地 | 種類 | 容量 | 固定費 | 対応顧客数 | 年間処理量 |
|---|---|---|---|---|---|---|
| DC_1 | Memphis, TN | フルラインDC | 500K units | $5M | 1,250 | 450K |
| DC_2 | Los Angeles, CA | 地域DC | 300K units | $4M | 800 | 280K |
コストの内訳:
| コスト項目 | 現状 | 提案 | 増減額 | 変化率 |
|---|---|---|---|---|
| 施設固定費 | $12M | $9M | -$3M | -25% |
| 輸送費 | $15M | $14M | -$1M | -7% |
| 在庫保有費 | $8M | $6M | -$2M | -25% |
| 合計 | $35M | $29M | -$6M | -17% |
サービスレベル:
| 指標 | 現状 | 提案 | 改善 |
|---|---|---|---|
| 平均距離 | 650 mi | 420 mi | -35% |
| 2日以内配送率 | 75% | 92% | +17 pts |
| 納期遵守率 | 89% | 95% | +6 pts |
導入計画:
- フェーズ1(1~6か月):Memphis に新しい DC_1 を開設します
- フェーズ2(7~12か月):輸送量を移行し、既存の DC を2か所閉鎖します
- フェーズ3(13~18か月):業務を最適化し、継続的に改善します
確認事項
より詳しい情報が必要な場合は、以下を確認してください。
- ネットワークの地理的範囲はどの程度ですか?(地域、国内、グローバル)
- この分析の主な目的は何ですか?(コスト、サービス、成長、集約)
- 現在のネットワークには施設がいくつありますか?
- 主な制約は何ですか?(予算、サービスレベル、既存の賃貸契約)
- どのようなデータを利用できますか?(顧客需要、施設コスト、輸送運賃)
- グリーンフィールド(新規設計)ですか、それともブラウンフィールド(既存ネットワークの最適化)ですか?
- 意思決定の期限と導入までの期間はどの程度ですか?
関連スキル
- facility-location-problem:数理最適化モデル向け
- distribution-center-network:多段階ネットワーク設計向け
- route-optimization:ネットワーク内の輸送向け
- inventory-optimization:ネットワーク全体の安全在庫向け
- supply-chain-analytics:ネットワークのパフォーマンス指標向け
- scenario-planning:需要の不確実性分析向け
- freight-optimization:輸送手段の選定向け