🎓 レベル:標準 | 重要度:A(必須)
📎 前提:経済的発注量EOQ(いくつ発注するか)・予測誤差の評価と追跡信号(σ_e→安全在庫の橋) | 確率の土台:正規分布(標準正規・標準化)(z=サービス水準の分位点) | 次:定量発注と定期発注
要点(BLUF)
- 経済的発注量EOQ は「需要一定・補充瞬時」の理想世界の話でした。現実は需要がばらつき、注文してから届くまで(リードタイム )にも在庫が減ります。この 期間の品切れリスクに備える緩衝が安全在庫 SSです。
- 守るべき相手はリードタイム需要 DLT(lead-time demand=補充が届くまでに出る需要)。一定リードタイム ・独立需要なら、DLT の平均は 、標準偏差は (分散が足し算だから )。
- いつ発注をかけるかの在庫水準が発注点 ROP。、。 は目標サイクルサービス水準 CSL の正規分位点 (確率の土台は 正規分布(標準正規・標準化))。
- 安全在庫はばらつき に比例し、リードタイムには** で効きます**( が4倍でも安全在庫は2倍)。「在庫切れを起こさないサイクルの割合(CSL)」と「需要を満たせた量の割合(フィルレート)」は別物——混同しないこと。
1. なぜ安全在庫が要るのか:守る相手は「リードタイム需要」
発注したら瞬時に届くなら、在庫が0になった瞬間に補充すればよく、安全在庫は不要です。現実にはリードタイム (発注から入荷までの日数)があり、その間も需要は出続けます。だから「在庫が** 期間ぶんの需要まで下がったら発注する」のが基本——この発注をかける在庫水準が発注点 ROP**です。
ところが需要は毎日同じではありません。リードタイム中にたまたま需要が多ければ、補充が届く前に在庫が尽きて品切れします。そこで、平均的なリードタイム需要に上乗せして持つ緩衝が安全在庫 SS。守るべき確率変数は、補充が届くまでに発生する需要の合計=リードタイム需要 DLTです。
flowchart LR ROP["在庫が発注点 ROP に低下"] -->|"発注をかける"| WAIT["リードタイム L 待つ<br/>(この間も需要が出る)"] WAIT --> RISK["リードタイム需要 DLT がどれだけ出るか"] RISK -->|"DLT が ROP 以下"| OK["在庫が持つ(補充到着)"] RISK -->|"DLT が ROP 超過"| NG["在庫切れ(安全在庫を食い破る)"]
2. リードタイム需要の平均と標準偏差
DLT は独立な日次需要の和なので、期待値は足し算・分散も足し算です。
平方根をとると、ばらつきはリードタイムの平方根で伸びます——ここが在庫設計の急所です。
平均は に比例(線形)するのに、標準偏差は でしか増えません。だからリードタイムが伸びるほど、平均需要に対する相対的なばらつきは縮みます(変動係数 が小さくなる)。それでも安全在庫は で増えるので、リードタイム短縮は在庫削減に直接効きます。
発注点とサービス水準
DLT が(中心極限定理で)おおむね正規分布 に従うとみなすと、発注点を
と置いたとき、そのサイクルで品切れしない確率(補充到着まで在庫が持つ確率)は
です。欲しいサービス水準 (例 95%)を決めれば、対応する (標準正規の分位点)が決まり、安全在庫 が出ます。(正規分位点)そのものの理論は 正規分布(標準正規・標準化) に譲り、ここでは scipy.stats.norm.ppf で値を取ります。
予測誤差からの接続:予測誤差の評価と追跡信号 では、予測誤差の標準偏差を と見積もりました。リードタイム1期なら 、一般には 。予測の外れ幅 がそのまま安全在庫の素材になります。。
3. サービス水準から z・SS・ROP を計算する(コード)
需要は1日平均 個・標準偏差 個、リードタイム 日。目標 CSL を 90/95/99% としたときの ・安全在庫・発注点を scipy.stats.norm.ppf で計算し、続けてリードタイムを伸ばすと安全在庫が で増えることを見ます。
import numpy as np
import pandas as pd
from scipy.stats import norm
# 需要:1日あたり平均 μ_d、標準偏差 σ_d。リードタイム L 日(一定・需要は独立)
mu_d = 50.0 # 1日あたり平均需要(個/日)
sigma_d = 12.0 # 1日あたり需要の標準偏差(個/日)
L = 4 # リードタイム(日)
# リードタイム需要 DLT の平均と標準偏差
mu_DLT = L * mu_d
sigma_DLT = sigma_d * np.sqrt(L)
print(f"リードタイム需要 DLT: 平均 μ_DLT = L·μ_d = {mu_DLT:.1f} 個")
print(f" 標準偏差 σ_DLT = σ_d·sqrt(L) = {sigma_DLT:.2f} 個")
print()
# 目標CSL → z = Φ^{-1}(CSL) → 安全在庫 SS = z·σ_DLT、発注点 ROP = μ_DLT + SS
print("CSL z=norm.ppf(CSL) SS=z·σ_DLT ROP=μ_DLT+SS")
for csl in [0.90, 0.95, 0.99]:
z = norm.ppf(csl)
SS = z * sigma_DLT
ROP = mu_DLT + SS
print(f"{csl:.2f} {z:7.4f} {SS:7.2f} {ROP:7.2f}")
print()
# リードタイムが伸びると安全在庫は sqrt(L) で増える(z=1.645, 95% 固定)
z95 = norm.ppf(0.95)
print(f"[L の効果] z={z95:.3f}(95%)固定。SS = z·σ_d·sqrt(L)")
rows = []
for Lx in [1, 2, 4, 8, 16]:
sdlt = sigma_d * np.sqrt(Lx)
rows.append({"L(日)": Lx, "sqrt(L)": np.sqrt(Lx), "σ_DLT": sdlt, "SS(95%)": z95 * sdlt})
print(pd.DataFrame(rows).to_string(index=False, float_format=lambda x: f"{x:.3f}"))
出力:
リードタイム需要 DLT: 平均 μ_DLT = L·μ_d = 200.0 個
標準偏差 σ_DLT = σ_d·sqrt(L) = 24.00 個
CSL z=norm.ppf(CSL) SS=z·σ_DLT ROP=μ_DLT+SS
0.90 1.2816 30.76 230.76
0.95 1.6449 39.48 239.48
0.99 2.3263 55.83 255.83
[L の効果] z=1.645(95%)固定。SS = z·σ_d·sqrt(L)
L(日) sqrt(L) σ_DLT SS(95%)
1 1.000 12.000 19.738
2 1.414 16.971 27.914
4 2.000 24.000 39.476
8 2.828 33.941 55.828
16 4.000 48.000 78.953
出力の意味:リードタイム需要は平均 200 個・標準偏差 24 個()。サービス水準を上げるほど が増え、安全在庫が膨らみます——90%なら で SS 30.8 個、95%で 39.5 個、99%で 55.8 個。注目は最後の1%の高さ:95→99%(4ポイント)に上げるだけで安全在庫は と4割増し。サービス水準の上澄みは高くつく(正規分布の裾が薄いので、わずかな確率を潰すのに大きな =在庫が要る)。下段の表は の効き方で、 を と4倍にしても、安全在庫は と2倍にしかなりません()。逆に言えば、リードタイムを に縮めれば安全在庫は半分になる——調達リードタイム短縮が在庫に効く理由です。
4. モンテカルロで欠品率を実証する(コード)
「 なら欠品率は 」は本当か。擬似需要でリードタイム需要を20万サイクルサンプリングし、設定した ROP を超える(=在庫切れ)割合を数えます。理屈どおりなら、(95%)で約5%、99%で約1%になるはずです。
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from scipy.stats import norm
rng = np.random.default_rng(7)
mu_d, sigma_d, L = 50.0, 12.0, 4
mu_DLT = L * mu_d
sigma_DLT = sigma_d * np.sqrt(L)
# 多数の発注サイクルをシミュレート:各サイクルで L 日分の需要を合計=DLT。
# 発注点 ROP を超えたら(DLT > ROP)在庫切れ。達成欠品率が 1-CSL になるか検証
n_cycles = 200000
print("目標CSL ROP 理論欠品率 実測欠品率(MC)")
for csl in [0.90, 0.95, 0.99]:
z = norm.ppf(csl)
ROP = mu_DLT + z * sigma_DLT
DLT = rng.normal(mu_d, sigma_d, size=(n_cycles, L)).sum(axis=1)
stockout_rate = np.mean(DLT > ROP)
print(f"{csl:.2f} {ROP:7.2f} {1 - csl:6.3f} {stockout_rate:7.4f}")
# z=1.645(95%)の DLT 分布・ROP・SS を図示
z = norm.ppf(0.95)
ROP = mu_DLT + z * sigma_DLT
DLT = rng.normal(mu_d, sigma_d, size=(n_cycles, L)).sum(axis=1)
emp = np.mean(DLT > ROP)
print(f"\n図の設定:CSL=95%, ROP={ROP:.2f}, SS={z * sigma_DLT:.2f}")
print(f" ROP 超過(欠品)割合 = {emp:.4f}(目標 0.05)")
plt.figure(figsize=(10, 5.5))
plt.hist(DLT, bins=80, density=True, color="#aec7e8", edgecolor="white", label="DLT 分布(MC)")
xs = np.linspace(DLT.min(), DLT.max(), 300)
plt.plot(xs, norm.pdf(xs, mu_DLT, sigma_DLT), color="#1f77b4", lw=2, label="正規近似")
plt.axvline(mu_DLT, color="gray", ls="--", label=f"μ_DLT={mu_DLT:.0f}")
plt.axvline(ROP, color="#d62728", lw=2, label=f"ROP={ROP:.1f}")
mask = xs >= ROP
plt.fill_between(xs, 0, norm.pdf(xs, mu_DLT, sigma_DLT), where=mask,
color="#d62728", alpha=0.3, label="欠品確率(約5%)")
plt.annotate("", xy=(ROP, 0.004), xytext=(mu_DLT, 0.004),
arrowprops=dict(arrowstyle="<->", color="green"))
plt.text((mu_DLT + ROP) / 2, 0.0043, f"安全在庫 SS={z * sigma_DLT:.1f}", ha="center", color="green")
plt.xlabel("リードタイム需要 DLT(個)"); plt.ylabel("確率密度")
plt.title("発注点 ROP=μ_DLT+z·σ_DLT:右裾の面積が欠品確率(CSL=95%→約5%)")
plt.legend(); plt.tight_layout(); plt.show()
出力:
目標CSL ROP 理論欠品率 実測欠品率(MC)
0.90 230.76 0.100 0.0996
0.95 239.48 0.050 0.0495
0.99 255.83 0.010 0.0101
図の設定:CSL=95%, ROP=239.48, SS=39.48
ROP 超過(欠品)割合 = 0.0496(目標 0.05)
出力の意味:実測の欠品率は 0.0996/0.0495/0.0101 で、理論値 0.10/0.05/0.01 と小数第3位までほぼ一致。「 の安全在庫を積めば、欠品は20サイクルに1回(5%)」が数値で裏取りできました。図は20万サイクルのリードタイム需要のヒストグラム(青)に正規近似(濃青)を重ねたもの。灰の破線が平均 、赤い線が発注点 、その間の緑の矢印が安全在庫 です。赤い線の右側の面積(約5%)がそのまま欠品確率——発注点を右にずらす(安全在庫を増やす)ほどこの裾が薄くなり、欠品が減ります。安全在庫とは、この右裾を許容水準まで削るために積む在庫だと、絵で腑に落ちます。
⚠️ よくある誤解
- 「安全在庫はリードタイムに比例する」ではない:比例するのは平均需要 のほう。安全在庫は で にしか増えません。 を倍にしても安全在庫は 倍。この差を取り違えると過剰/過少在庫になります。
- 「サイクルサービス水準とフィルレートは同じ」ではない:CSL は「在庫切れを起こさない発注サイクルの割合」(イベントの確率)、フィルレートは「需要を満たせた数量の割合」(量の比)です。同じ安全在庫でも、品切れサイクルでも需要の大半は満たせるのでフィルレートは CSL より高く出るのが普通。フィルレートは標準正規損失関数 を使い で評価します(在庫量 が大きいほど高い)。目標が「サイクル」か「数量」かで必要在庫が変わるので、どちらの指標を約束しているかを最初に決めます。
- 「リードタイムが変動しても でよい」ではない:リードタイム自体がばらつく( が確率変数で標準偏差 )なら、需要の変動とリードタイムの変動が合成され 。第2項(リードタイムのばらつき × 平均需要)が大きいことも多く、リードタイムの安定化が安全在庫削減に効きます。
- 「正規分布でいつでも近似できる」ではない:たまにしか出ない断続需要(多くの日が0で、たまに大口)は正規から大きく外れ、 方式は当てになりません。ポアソン/負の二項や、需要間隔と数量を別に扱う手法(クロストン法など)で別手当てします(要最新確認)。
- 「安全在庫はコストで決める」ではない(ここでは):本稿はサービス水準(CSL)を所与として連続監視の発注点を設計しました。品切れ損失と保管コストの綱引きで最適在庫を決めるコストベース(限界比・新聞売り子)は、目的関数が違う別問題で、第9章 確率的在庫モデルで扱います。
関連ノート
- 経済的発注量EOQ(いくつ発注するか。EOQ の上に安全在庫を積む)
- 定量発注と定期発注(次のトピック・発注点 ROP を方式に組み込む。定期は保護期間が に伸びる)
- 予測誤差の評価と追跡信号( → 安全在庫の素材)
- 正規分布(標準正規・標準化)(統計・ 分位点の土台)
- 第9章 確率的在庫モデル(単一期=新聞売り子。コストベースの臨界比)
- オペレーションズ・マネジメント 全体目次