Mímisbrunnr知恵の泉

← オペレーションズマネジメント 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:安全在庫と発注点(安全在庫 zσdLz\sigma_d\sqrt{L}・リードタイムが L\sqrt{L} で効く)・ボトルネックとキャパシティ(施設・能力の制約) | 関連:ブルウィップ効果在庫集約とリスクプーリング | 次:ブルウィップ効果

要点(BLUF)

1. サプライチェーンとは:供給のネットワーク

これまでの章は、工場やコールセンターという1つの拠点の中でフロー・在庫・能力を設計してきました。現実の「もの」は、原材料の供給者から始まり、製造され、流通センターを経て小売へ運ばれ、最後に顧客へ届きます。この多段のネットワーク全体を対象にするのがサプライチェーン・マネジメント(SCM)です。

flowchart LR
  SUP["供給者<br/>(部品・原料)"] -->|"輸送・リードタイム"| MFG["製造"]
  MFG -->|"輸送"| DC["流通センター<br/>(在庫を集約)"]
  DC -->|"輸送"| RET["小売<br/>(分散在庫)"]
  RET --> CUS["顧客"]

各矢印には輸送(コストと時間)が、各箱には在庫と施設が伴います。SCM の問いは「どこに在庫を置き、どの速さで運び、どこに施設を構えるか」——その答えはすべて、次の1本の軸に集約されます。

2. 中心のトレードオフ:効率 vs 応答性

SC 設計のほぼすべての判断は、効率(efficiency)と応答性(responsiveness)の綱引きに還元できます。

両者は基本的に逆を向きます。応答性を上げる手段(空輸・近接在庫・余剰能力)はたいていコストを押し上げ、効率を上げる手段(集約・大ロット・低在庫)はたいてい応答を遅らせます。だから「どちらも最高に」は不可能で、どこでバランスを取るかが設計です。

製品にSCを合わせる(Fisher のマッチング)

ではどちらに寄せるべきか。答えは製品の需要特性で決まります(Fisher, 1997)。

機能的製品(functional)革新的製品(innovative)
需要安定・予測しやすい変動大・予測しにくい(高 σd\sigma_d
利益率低い高い
食品・日用品・電池新型ガジェット・ファッション
欠品の痛み小さい(代替が効く)大きい(機会損失が高利益)
最適なSC効率重視(コスト最小)応答性重視(在庫・能力に余裕)

機能的製品は欠品しても損失が小さく需要も読めるので、徹底的に安く作るのが正解。革新的製品は1個の欠品が大きな利益を逃し、需要も読めないので、多少高くても速く柔軟に応える体制が正解です。製品と SC のミスマッチ——安定品に高コストの応答的SC、流行品に低在庫の効率的SC——が最大の失敗パターンです。

3. 在庫の3種類とプッシュ/プル

SC の在庫は役割で3つに分かれ、それぞれ別の要因で増減します。

リードタイムを短くすると、安全在庫(L\sqrt{L})と輸送中在庫(LL)の両方が減ります。これが「速い輸送・短い調達」が在庫を直接削る理由です。

プッシュ vs プルも同じ軸の別表現です。プッシュ(push)は予測に基づき先に作って在庫を前に出す——効率的だが予測が外れると過剰/欠品。プル(pull)は実需を見てから引いて作る——応答的だが能力に余裕が要る。多くのSCは「上流はプッシュ・下流はプル」の境界(push-pull boundary)をどこに置くかを設計します。

4. 総コストとリードタイムの効き方

SC の設計判断は、関連する総コストを足し合わせて比較します。1製品・年間で、

総コスト=ctD輸送  +  Q2hサイクル在庫  +  zσdLh安全在庫  +  dLh輸送中在庫  +  F施設\text{総コスト} = \underbrace{c_t\,D}_{\text{輸送}} \;+\; \underbrace{\frac{Q}{2}h}_{\text{サイクル在庫}} \;+\; \underbrace{z\,\sigma_d\sqrt{L}\,h}_{\text{安全在庫}} \;+\; \underbrace{d\,L\,h}_{\text{輸送中在庫}} \;+\; \underbrace{F}_{\text{施設}}

ここで ctc_t は1個あたり輸送費、DD は年間需要、hh は1個あたり年間保管費、d=D/営業日d=D/\text{営業日} は日次需要、LL はリードタイム、FF は施設の固定費です。

注目すべきはリードタイム LL の効き方の非対称です。サイクル在庫は Q/2Q/2 で**LL に依存しないのに対し、安全在庫は L\sqrt{L}、輸送中在庫は LL、つまりリードタイムを縮めると在庫費が二重に下がります**。一方で速い輸送は ctc_t(輸送費)を押し上げる。この綱引きが輸送モード選択——速くて高い空輸か、遅くて安い海上輸送か——の核心です。

そして、安全在庫の項に σd\sigma_d が掛かっていることが効いてきます。需要のばらつき σd\sigma_d が大きい(=革新的製品)ほど、長いリードタイムが背負う安全在庫 zσdLz\sigma_d\sqrt{L} が膨らみ、速い輸送の価値が上がる。次のコードでこれを定量化します。

5. 輸送モード選択:σ_d が大きいほど速い輸送が有利(コード)

高付加価値で需要が読みにくい製品(年間 D=12000D=12000 個・保管費 h=150h=150 円/個/年)を、航空(速い・高コスト・L=4L=4 日)で運ぶか海上(遅い・低コスト・L=36L=36 日)で運ぶかを比べます。サイクル在庫は EOQ で決まり両モード共通なので、モード選択を分けるのは輸送費(海上が有利)と安全在庫 zσdLz\sigma_d\sqrt{L}(航空が有利)だけ。需要のばらつき σd\sigma_d を振って、勝者がどこで入れ替わるかを見ます。

import numpy as np
import pandas as pd

# --- 前提(高付加価値で需要が読みにくい「革新的製品」を想定)---
D = 12000.0      # 年間需要(個/年)
days = 240       # 営業日/年
d_day = D / days # 1日あたり平均需要
h = 150.0        # 1個あたり年間保管費(円/個/年)=高付加価値
S = 500.0        # 1回あたり発注(船積み)固定費
z = 1.645        # 95% サービス水準の安全係数

# サイクル在庫は EOQ で決まり L に依存しない → 両モード共通
Q = np.sqrt(2 * D * S / h)
cycle_cost = (Q / 2) * h
print(f"日次平均需要 d_day = {d_day:.0f} 個/日, EOQ Q* = {Q:.2f} 個")
print(f"サイクル在庫費 = (Q/2)*h = {cycle_cost:.1f} 円/年(両モード共通・L に依存しない)\n")

# 2モード:航空(速い・高コスト・短い L)/海上(遅い・低コスト・長い L)
def costs(c_t, L, sigma_d):
    transport = c_t * D                       # 年間輸送費
    safety_units = z * sigma_d * np.sqrt(L)   # 安全在庫(個)= z*sigma_d*sqrt(L)
    safety = safety_units * h                 # 年間保管費
    return transport, cycle_cost, safety, transport + cycle_cost + safety

# sigma_d を 5->50 に振り、両モードの総コストと勝者
rows = []
for sigma_d in [5, 15, 25, 35, 50]:
    air = costs(30.0, 4, sigma_d)
    ocean = costs(28.0, 36, sigma_d)
    diff = air[3] - ocean[3]
    rows.append({
        "sigma_d": sigma_d,
        "航空_総コスト": air[3],
        "海上_総コスト": ocean[3],
        "差(航空-海上)": diff,
        "勝者": "航空" if diff < 0 else "海上",
    })
df = pd.DataFrame(rows)
print(df.to_string(index=False, float_format=lambda x: f"{x:.1f}"))

print("\n[内訳・sigma_d=25 のとき(円/年)]")
for name, (c_t, L) in [("航空", (30.0, 4)), ("海上", (28.0, 36))]:
    tr, cy, sf, tot = costs(c_t, L, 25)
    print(f"{name}: 輸送={tr:.0f}  サイクル={cy:.1f}  安全在庫={sf:.1f}  合計={tot:.1f}")

# 損益分岐の sigma_d(両モードの総コストが等しくなる点)
sigma_star = (30.0 - 28.0) * D / (z * h * (np.sqrt(36) - np.sqrt(4)))
print(f"\n損益分岐 sigma_d* = {sigma_star:.2f}(これを超えると速い航空が有利)")

出力:

日次平均需要 d_day = 50 個/日, EOQ Q* = 282.84 個
サイクル在庫費 = (Q/2)*h = 21213.2 円/年(両モード共通・L に依存しない)

 sigma_d  航空_総コスト  海上_総コスト  差(航空-海上) 勝者
       5 383680.7 364615.7   19065.0 海上
      15 388615.7 379420.7    9195.0 海上
      25 393550.7 394225.7    -675.0 航空
      35 398485.7 409030.7  -10545.0 航空
      50 405888.2 431238.2  -25350.0 航空

[内訳・sigma_d=25 のとき(円/年)]
航空: 輸送=360000  サイクル=21213.2  安全在庫=12337.5  合計=393550.7
海上: 輸送=336000  サイクル=21213.2  安全在庫=37012.5  合計=394225.7

損益分岐 sigma_d* = 24.32(これを超えると速い航空が有利)

出力の意味:海上は航空より輸送費が年 24000 円安い336000336000 vs 360000360000(3028)×12000(30-28)\times12000)。これが海上の取り柄です。一方で海上はリードタイムが長い(L=36L=36)ぶん安全在庫が重く、内訳を見ると σd=25\sigma_d=25 で安全在庫費は海上 37012.5 円 vs 航空 12337.5 円——航空が約 24675 円も軽い。輸送で 24000 円損するが安全在庫で 24675 円得するので、σd=25\sigma_d=25 では航空が僅差(675-675 円)で勝ちます。表の通り、σd\sigma_d が小さい(需要が読みやすい)うちは安全在庫の差が小さく海上が有利(σd=5,15\sigma_d=5,15)ですが、σd\sigma_d が大きくなるほど安全在庫の差 zh(364)σdz\,h(\sqrt{36}-\sqrt{4})\sigma_d が開き、損益分岐 σd\*=24.32\sigma_d^\*=24.32 を超えると速い航空が逆転します。「需要が読みにくい製品ほど速い輸送(応答性)に金を払う価値がある」——これが革新的製品が応答性重視になる数理的な理由です。

6. 効率-応答性フロンティア:支配される選択肢を捨てる(コード)

輸送モードに限らず、SC 構成(モード × 在庫水準 × 倉庫配置)はたくさんあります。それぞれを (年間総コスト, 応答時間)(\text{年間総コスト},\ \text{応答時間}) の1点として平面に置くと、両方とも小さい(安くて速い)ほど良いので、左下に向かうほど優秀です。どの案からも改善できない境界が効率-応答性フロンティア(パレート最適)。フロンティアより右上にある案は、**もっと安くてもっと速い案が存在する=支配される(dominated)**ので、検討から外せます。

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib

# 各SC構成の (年間総コスト[万円], 応答時間[日])。小さいほど良い両軸
options = {
    "海上・低在庫":      (380, 36),
    "海上・高在庫":      (405, 33),
    "鉄道":              (395, 20),
    "航空・低在庫":      (420, 6),
    "航空・高在庫(JIT)": (450, 3),
    "分散倉庫+航空":     (480, 2),
    "非効率A":           (430, 25),
    "非効率B":           (460, 10),
}
names = list(options.keys())
cost = np.array([options[n][0] for n in names], float)
resp = np.array([options[n][1] for n in names], float)

# パレート最適:点 i は、ある j が「コスト以下 かつ 応答以下」で
# 少なくとも一方が真に小さいなら支配される(dominated)
def is_dominated(i):
    for j in range(len(names)):
        if j == i:
            continue
        if cost[j] <= cost[i] and resp[j] <= resp[i] and (cost[j] < cost[i] or resp[j] < resp[i]):
            return True
    return False

dominated = np.array([is_dominated(i) for i in range(len(names))])
print("構成              コスト(万円)  応答(日)  判定")
for i, nm in enumerate(names):
    tag = "支配される" if dominated[i] else "フロンティア"
    print(f"{nm:16s} {cost[i]:7.0f}    {resp[i]:5.0f}    {tag}")

front_idx = [i for i in range(len(names)) if not dominated[i]]
front_idx.sort(key=lambda i: cost[i])
print("\nフロンティア(効率-応答性):" + " -> ".join(names[i] for i in front_idx))

# 図:フロンティアを線で結び、支配される点を赤×で示す
plt.figure(figsize=(10, 6))
plt.plot(cost[front_idx], resp[front_idx], "-", color="#1f77b4", lw=2, zorder=1,
         label="効率-応答性フロンティア")
first_dom = int(np.where(dominated)[0][0])
for i in range(len(names)):
    if dominated[i]:
        plt.scatter(cost[i], resp[i], color="#d62728", marker="x", s=110, zorder=3,
                    label="支配される選択肢" if i == first_dom else None)
    else:
        plt.scatter(cost[i], resp[i], color="#1f77b4", s=90, zorder=3,
                    label="パレート最適" if i == front_idx[0] else None)
    plt.annotate(names[i], (cost[i], resp[i]), textcoords="offset points",
                 xytext=(8, 5), fontsize=9)
plt.xlabel("年間総コスト(万円)=効率(右ほど高コスト)")
plt.ylabel("応答時間(日)=応答性(下ほど速い)")
plt.title("効率-応答性フロンティア:左下が理想・赤×は他案に支配される")
plt.legend(); plt.grid(alpha=0.3); plt.tight_layout(); plt.show()

出力:

構成              コスト(万円)  応答(日)  判定
海上・低在庫               380       36    フロンティア
海上・高在庫               405       33    支配される
鉄道                   395       20    フロンティア
航空・低在庫               420        6    フロンティア
航空・高在庫(JIT)          450        3    フロンティア
分散倉庫+航空              480        2    フロンティア
非効率A                 430       25    支配される
非効率B                 460       10    支配される

フロンティア(効率-応答性):海上・低在庫 -> 鉄道 -> 航空・低在庫 -> 航空・高在庫(JIT) -> 分散倉庫+航空

出力の意味:8案のうち5案がフロンティア(パレート最適)で、コストの安い順に「海上・低在庫(380万・36日)→ 鉄道(395万・20日)→ 航空・低在庫(420万・6日)→ 航空・高在庫JIT(450万・3日)→ 分散倉庫+航空(480万・2日)」と並びます。図ではこの5点を結ぶ右下がりの青い線が境界で、安くしようとすれば遅く、速くしようとすれば高くなるというトレードオフそのものです。一方、3案は赤×=支配される。たとえば「海上・高在庫(405万・33日)」は「鉄道(395万・20日)」より高くて遅い;「非効率A(430万・25日)」も鉄道に、「非効率B(460万・10日)」は「航空・低在庫(420万・6日)」に、どちらもコストでも応答でも負けています。支配される案は検討に値しません——まずこれらを捨て、残ったフロンティア上で「自社の製品(機能的か革新的か)はどこを選ぶべきか」を考えるのが SC 設計です。なお、情報共有やプロセス改善はフロンティアそのものを左下へ押し下げる(同じ応答性をより安く)ので、トレードオフを「ずらす」打ち手になります。

⚠️ よくある誤解

関連ノート