STEP 38:在庫最適化

📦 STEP 38: 在庫最適化

データを活用して在庫コストを最小化しながら欠品を防ごう

📋 このステップで学ぶこと

  • 経済的発注量(EOQ)の計算と意味
  • 安全在庫の設計方法
  • 欠品リスクと過剰在庫のバランス
  • 発注点(いつ発注するか)の決定
  • PythonとExcelでの在庫最適化実装

🔍 1. 在庫管理の基礎

なぜ在庫管理が重要なのか

在庫管理は、ビジネスの成功に直結する重要な課題です。しかし、在庫管理には相反する2つの目標があり、そのバランスを取ることが難しいのです。

📌 在庫管理の2つの目標(トレードオフの関係)

目標1:在庫コストを減らしたい

在庫を持つとお金がかかります。
・倉庫代(保管場所の費用)
・人件費(在庫管理の作業)
・資金の拘束(在庫に使ったお金は他に使えない)
・売れ残りリスク(古くなると売れなくなる)

→ だから在庫を減らしたい!

目標2:欠品を防ぎたい

在庫がないと売上を逃します。
・販売機会の損失(お客さんが来ても売れない)
・顧客満足度の低下(欲しいものがないと不満)
・ライバル店への流出(他の店で買われる)
・ブランドイメージの悪化(品揃えが悪い店と思われる)

→ だから在庫を増やしたい!

解決策:データを使って最適なバランス点を見つける!

在庫に関わる3つのコスト

在庫を管理するときは、以下の3つのコストを考える必要があります。これらの合計を最小化することが目標です。

💡 在庫コストの内訳

① 発注コスト(Ordering Cost)

商品を発注するたびにかかる費用
・発注業務の人件費(注文書作成、電話など)
・運送費(配送してもらう費用)
・検品費用(届いた商品を確認する作業)

特徴:発注回数が多いほど、コストが増える
→ 1回の発注量を増やせば、発注回数が減り、コスト削減!

② 保管コスト(Holding Cost)

在庫を持ち続けることでかかる費用
・倉庫の賃料
・在庫管理の人件費
・保険料
・資金の金利(そのお金を銀行に預けていたら利息がついたはず)

特徴:在庫量が多いほど、コストが増える
→ 在庫を減らせば、コスト削減!

③ 欠品コスト(Stockout Cost)

在庫がなくて売れなかったときの損失
・売上機会の損失(売れたはずの利益)
・緊急発注の追加費用(急いで取り寄せると高い)
・顧客離れ(次からは他の店で買う)

特徴:在庫が少ないほど、リスクが増える
→ 適切な安全在庫で防ぐ!

⚠️ 発注コストと保管コストは逆の関係

1回の発注量を増やすと…

✅ 発注コスト → 減る(発注回数が減るから)
❌ 保管コスト → 増える(在庫が増えるから)

1回の発注量を減らすと…

❌ 発注コスト → 増える(発注回数が増えるから)
✅ 保管コスト → 減る(在庫が減るから)

→ このバランスが取れる点を見つけるのがEOQ!

📐 2. 経済的発注量(EOQ)の計算

EOQとは何か

EOQ(Economic Order Quantity)は、日本語で「経済的発注量」と呼ばれます。これは、総コスト(発注コスト+保管コスト)を最小化する、1回あたりの最適な発注量のことです。

💡 EOQの公式

EOQ = √(2 × D × S ÷ H)

記号の意味:
D = 年間需要量(1年間で売れる個数)
S = 1回あたりの発注コスト(円)
H = 1個あたりの年間保管コスト(円)

なぜルート(√)なのか?
発注コストと保管コストの曲線が交わる点が最適解で、数学的に計算するとこの公式になります。難しければ「この公式で計算すれば最適な発注量が分かる」と覚えてOKです!

具体例で計算してみよう

💡 例題:文房具店の在庫管理

条件:
・年間需要量(D)= 10,000個/年
・発注コスト(S)= 5,000円/回
・保管コスト(H)= 200円/個・年

計算手順:

Step 1:公式に数字を代入
EOQ = √(2 × 10,000 × 5,000 ÷ 200)

Step 2:かけ算を計算
= √(100,000,000 ÷ 200)
= √(500,000)

Step 3:ルートを計算
= 707個

答え:1回あたり約700個を発注するのが最適!

EOQを使うとどうなるか

📌 EOQ(707個)で発注した場合の年間コスト

① 年間発注回数
= 年間需要量 ÷ EOQ
= 10,000 ÷ 707
= 約14回/年(約26日に1回発注)

② 年間発注コスト
= 発注回数 × 1回の発注コスト
= 14回 × 5,000円
= 70,700円

③ 年間保管コスト
= 平均在庫 × 保管コスト
= (707 ÷ 2)× 200円
= 353.5 × 200
= 70,700円

④ 年間総コスト
= 発注コスト + 保管コスト
= 70,700 + 70,700
= 141,400円

※ EOQでは発注コストと保管コストがほぼ等しくなります。これがバランスが取れている証拠です!

なぜ「平均在庫 = EOQ ÷ 2」なのか

📝 平均在庫の考え方

在庫の動き:

・発注品が届く → 在庫がEOQ個になる
・毎日売れていく → 在庫が徐々に減る
・在庫が0になる直前 → また発注品が届く

つまり、在庫は「EOQ個 → 0個 → EOQ個 → 0個」と変動します。

平均すると:
最大(EOQ)と最小(0)の中間 = EOQ ÷ 2

だから保管コストは「EOQ ÷ 2 × 保管単価」で計算します。

Pythonでの実装

それでは、PythonでEOQを計算してみましょう。コードを段階的に説明します。

Step 1:必要なライブラリの読み込み

# ============================================ # ライブラリの読み込み # ============================================ # numpy: 数学計算に使う(ルート計算など) import numpy as np # matplotlib: グラフを描くためのライブラリ import matplotlib.pyplot as plt # pandas: データを表形式で扱うライブラリ import pandas as pd # 日本語フォント設定(グラフに日本語を表示するため) plt.rcParams[‘font.sans-serif’] = [‘Arial Unicode MS’, ‘Yu Gothic’, ‘Hiragino Sans’] plt.rcParams[‘axes.unicode_minus’] = False

Step 2:EOQを計算する関数を作成

# ============================================ # EOQ計算関数 # ============================================ # 関数を定義すると、何度でも使い回せて便利 def calculate_eoq(annual_demand, ordering_cost, holding_cost): “”” 経済的発注量(EOQ)を計算する関数 引数: annual_demand: 年間需要量(個) ordering_cost: 1回あたりの発注コスト(円) holding_cost: 1個あたりの年間保管コスト(円) 戻り値: EOQ(最適な1回あたりの発注量) “”” # EOQの公式:√(2 × D × S / H) # np.sqrt() はルート(平方根)を計算する関数 eoq = np.sqrt(2 * annual_demand * ordering_cost / holding_cost) return eoq

Step 3:パラメータを設定してEOQを計算

# ============================================ # パラメータ設定 # ============================================ D = 10000 # 年間需要量(個):年間10,000個売れる S = 5000 # 発注コスト(円/回):1回の発注に5,000円かかる H = 200 # 保管コスト(円/個・年):1個を1年保管するのに200円 # ============================================ # EOQ計算 # ============================================ eoq = calculate_eoq(D, S, H) # 結果を表示 print(“【経済的発注量(EOQ)の計算結果】”) print() print(f”年間需要量: {D:,}個”) print(f”発注コスト: {S:,}円/回”) print(f”保管コスト: {H:,}円/個・年”) print() print(f”経済的発注量(EOQ): {eoq:.0f}個”)
# 出力結果 【経済的発注量(EOQ)の計算結果】 年間需要量: 10,000個 発注コスト: 5,000円/回 保管コスト: 200円/個・年 経済的発注量(EOQ): 707個

Step 4:年間コストを計算

# ============================================ # 年間コストの計算 # ============================================ # 年間発注回数 = 年間需要量 ÷ EOQ annual_orders = D / eoq print(f”年間発注回数: {annual_orders:.1f}回”) # 年間発注コスト = 発注回数 × 1回の発注コスト ordering_cost_total = annual_orders * S print(f”年間発注コスト: {ordering_cost_total:,.0f}円”) # 年間保管コスト = 平均在庫 × 保管コスト # 平均在庫 = EOQ ÷ 2(在庫はEOQ〜0の間を動くので平均は半分) holding_cost_total = (eoq / 2) * H print(f”年間保管コスト: {holding_cost_total:,.0f}円”) # 年間総コスト = 発注コスト + 保管コスト total_cost = ordering_cost_total + holding_cost_total print(f”年間総コスト: {total_cost:,.0f}円”)
# 出力結果 年間発注回数: 14.1回 年間発注コスト: 70,711円 年間保管コスト: 70,711円 年間総コスト: 141,421円

Step 5:発注量を変えた場合のコスト比較(グラフ作成)

※ 以下のコードは横スクロールで全体を確認できます。

# ============================================ # 発注量を変えた場合のコスト分析 # ============================================ # 発注量を100〜2000個まで変化させてみる order_quantities = np.arange(100, 2001, 50) # 100, 150, 200, …, 2000 # 各発注量での総コストを計算する関数 def calculate_total_cost(Q, D, S, H): “”” 総コストを計算する関数 Q: 発注量 D: 年間需要量 S: 発注コスト H: 保管コスト “”” ordering_cost = (D / Q) * S # 発注コスト = (需要÷発注量) × 単価 holding_cost = (Q / 2) * H # 保管コスト = (平均在庫) × 単価 total_cost = ordering_cost + holding_cost return ordering_cost, holding_cost, total_cost # 各発注量でのコストを計算 results = [] for Q in order_quantities: oc, hc, tc = calculate_total_cost(Q, D, S, H) results.append({ ‘発注量’: Q, ‘発注コスト’: oc, ‘保管コスト’: hc, ‘総コスト’: tc }) # DataFrameに変換 df_cost = pd.DataFrame(results) # ============================================ # グラフ作成 # ============================================ plt.figure(figsize=(12, 6)) # 発注コストの曲線(発注量が増えると減る) plt.plot(df_cost[‘発注量’], df_cost[‘発注コスト’], label=’発注コスト’, color=’#ff6b6b’, linewidth=2) # 保管コストの曲線(発注量が増えると増える) plt.plot(df_cost[‘発注量’], df_cost[‘保管コスト’], label=’保管コスト’, color=’#4ecdc4′, linewidth=2) # 総コストの曲線(U字型になる) plt.plot(df_cost[‘発注量’], df_cost[‘総コスト’], label=’総コスト’, color=’#45b7d1′, linewidth=3) # EOQの位置に縦線を引く plt.axvline(x=eoq, color=’orange’, linestyle=’–‘, linewidth=2, label=f’EOQ = {eoq:.0f}個’) # 最適点にマーカーを付ける plt.scatter([eoq], [total_cost], color=’red’, s=200, zorder=5) # グラフの設定 plt.xlabel(‘発注量(個)’, fontsize=12) plt.ylabel(‘年間コスト(円)’, fontsize=12) plt.title(‘発注量と年間コストの関係’, fontsize=14, fontweight=’bold’) plt.legend(fontsize=11) plt.grid(alpha=0.3) plt.tight_layout() plt.show()
📝 グラフの読み方

発注コスト(赤い線)
→ 発注量が増えると、発注回数が減るので下がる

保管コスト(緑の線)
→ 発注量が増えると、在庫が増えるので上がる

総コスト(青い線)
→ 2つのコストの合計。U字型になる

EOQ(オレンジの点線)
→ U字のが最適点。ここでは707個

Excelでの実装

【ExcelでEOQを計算する方法】 ■ データ入力(例) A列 B列 ───────────────── 年間需要量 10000 発注コスト 5000 保管コスト 200 ■ EOQ計算式(B5セルに入力) =SQRT(2*B1*B2/B3) 結果:707(個) ■ 年間コスト計算 B7: 年間発注回数 =B1/B5 B8: 年間発注コスト =B7*B2 B9: 年間保管コスト =(B5/2)*B3 B10: 年間総コスト =B8+B9 ■ 感度分析(発注量を変えた場合のコスト) データ → What-If分析 → データテーブル ・行入力セルに発注量を設定 ・発注量100〜2000で総コストを計算 ・グラフ化してU字カーブを確認

🛡️ 3. 安全在庫の設計

安全在庫とは何か

EOQは「需要が一定」という前提で計算しました。しかし、現実の世界では…

⚠️ 現実の不確実性

・需要は毎日変動する(急に売れる日もあれば、売れない日も)
・リードタイム(発注から届くまでの日数)も変動する
・予測は必ず外れる

→ この不確実性に備えて、安全在庫(バッファ)を持つ!

📌 安全在庫(Safety Stock)の定義

安全在庫とは、需要の変動やリードタイムの遅れに備えて、追加で持っておく在庫のこと。

イメージ:
「普通は必要ないけど、万が一のために持っておくお守り」

安全在庫がないと:
予想外に売れた → 在庫切れ → 販売機会を逃す

安全在庫があると:
予想外に売れた → 安全在庫で対応 → 販売機会を逃さない

安全在庫の計算式

💡 安全在庫の公式

安全在庫 = Z × √(リードタイム) × σ

記号の意味:
Z = 安全係数(サービス率から決まる)
リードタイム = 発注から届くまでの日数
σ(シグマ) = 日次需要の標準偏差(需要のばらつき)

サービス率と安全係数(Z)の関係:
・サービス率90%(100日中90日は欠品しない)→ Z = 1.28
・サービス率95%(100日中95日は欠品しない)→ Z = 1.65
・サービス率99%(100日中99日は欠品しない)→ Z = 2.33

サービス率の考え方

💡 サービス率とは

サービス率 = 欠品しない確率

サービス率95%の意味:
「100回の需要のうち、95回は欠品せずに対応できる」

逆に言うと:
「100回のうち5回は欠品する可能性がある」

サービス率を上げると:
・安全在庫が増える
・欠品リスクが下がる
・保管コストが上がる

→ トレードオフの関係!商品の重要度に応じて設定する

サービス率 安全係数(Z) 適用例
90% 1.28 低価格品、代替品がある商品
95% 1.65 一般的な商品(推奨)
99% 2.33 重要商品、欠品が許されない商品

具体例で計算してみよう

💡 例題:安全在庫の計算

条件:
・日次平均需要 = 30個/日
・日次需要の標準偏差(σ)= 10個
・リードタイム = 7日
・サービス率 = 95%(Z = 1.65)

計算手順:

Step 1:公式に数字を代入
安全在庫 = Z × √(リードタイム) × σ
= 1.65 × √7 × 10

Step 2:√7を計算
√7 = 2.65

Step 3:掛け算
= 1.65 × 2.65 × 10
= 44個

答え:安全在庫として44個を持っておく!
これにより、95%の確率で欠品を防げる。

発注点(Reorder Point)の計算

発注点とは、「在庫がこの数量を下回ったら発注する」という基準値です。

💡 発注点の公式

発注点 = リードタイム需要 + 安全在庫

リードタイム需要とは:
発注してから届くまでの間に売れる予想数量
= 日次平均需要 × リードタイム(日)

計算例:
リードタイム需要 = 30個/日 × 7日 = 210個
安全在庫 = 44個
発注点 = 210 + 44 = 254個

運用ルール:
在庫が254個を下回ったら、EOQ分(707個)を発注する!

📝 在庫の動きのイメージ

Day 0:EOQ分が届く → 在庫751個(707 + 安全在庫44)
毎日30個ずつ売れる
Day 16:在庫が254個に → 発注!
リードタイム7日間も売れ続ける
Day 23:在庫が44個(安全在庫のみ)→ EOQ分が届く
在庫751個に回復

※ 需要が予想通りなら、安全在庫は減らない
※ 需要が多かった日は、安全在庫が使われる

Pythonでの実装

Step 1:安全在庫と発注点の計算

# ============================================ # 安全在庫と発注点の計算 # ============================================ from scipy import stats # scipy.stats: 統計関数のライブラリ # 正規分布の逆関数を使って安全係数を計算するために使う def calculate_safety_stock(lead_time_days, demand_std, service_level=0.95): “”” 安全在庫を計算する関数 引数: lead_time_days: リードタイム(日) demand_std: 日次需要の標準偏差(個) service_level: サービス率(0〜1) 戻り値: safety_stock: 安全在庫(個) z_score: 安全係数 “”” # stats.norm.ppf(): 正規分布の逆関数 # サービス率からZ値(安全係数)を計算 z_score = stats.norm.ppf(service_level) # 安全在庫の公式:Z × √(リードタイム) × σ safety_stock = z_score * np.sqrt(lead_time_days) * demand_std return safety_stock, z_score def calculate_reorder_point(avg_daily_demand, lead_time_days, safety_stock): “”” 発注点を計算する関数 引数: avg_daily_demand: 日次平均需要(個) lead_time_days: リードタイム(日) safety_stock: 安全在庫(個) 戻り値: reorder_point: 発注点(個) lead_time_demand: リードタイム需要(個) “”” # リードタイム需要 = 日次平均需要 × リードタイム lead_time_demand = avg_daily_demand * lead_time_days # 発注点 = リードタイム需要 + 安全在庫 reorder_point = lead_time_demand + safety_stock return reorder_point, lead_time_demand

Step 2:パラメータを設定して計算

# ============================================ # パラメータ設定 # ============================================ avg_daily_demand = 30 # 日次平均需要(個) demand_std = 10 # 日次需要の標準偏差(個) lead_time = 7 # リードタイム(日) service_level = 0.95 # サービス率(95%) # ============================================ # 安全在庫の計算 # ============================================ safety_stock, z_score = calculate_safety_stock(lead_time, demand_std, service_level) print(“【安全在庫の計算】”) print() print(f”日次平均需要: {avg_daily_demand}個/日”) print(f”日次需要の標準偏差: {demand_std}個”) print(f”リードタイム: {lead_time}日”) print(f”サービス率: {service_level*100:.0f}%”) print(f”安全係数(Z値): {z_score:.2f}”) print() print(f”安全在庫: {safety_stock:.0f}個”) # ============================================ # 発注点の計算 # ============================================ reorder_point, lead_time_demand = calculate_reorder_point( avg_daily_demand, lead_time, safety_stock ) print() print(“【発注点の計算】”) print() print(f”リードタイム需要: {lead_time_demand:.0f}個”) print(f”安全在庫: {safety_stock:.0f}個”) print(f”発注点: {reorder_point:.0f}個”)
# 出力結果 【安全在庫の計算】 日次平均需要: 30個/日 日次需要の標準偏差: 10個 リードタイム: 7日 サービス率: 95% 安全係数(Z値): 1.65 安全在庫: 44個 【発注点の計算】 リードタイム需要: 210個 安全在庫: 44個 発注点: 254個

Step 3:在庫管理パラメータの統合

# ============================================ # 在庫管理パラメータの統合 # ============================================ # 年間需要から年間発注パラメータを計算 annual_demand = avg_daily_demand * 365 # 年間需要量 # 発注コストと保管コスト(前のセクションの値) S = 5000 # 発注コスト H = 200 # 保管コスト # EOQの計算 eoq_value = calculate_eoq(annual_demand, S, H) print(“【在庫管理パラメータまとめ】”) print() print(f”年間需要: {annual_demand:,}個”) print(f”経済的発注量(EOQ): {eoq_value:.0f}個”) print(f”発注点: {reorder_point:.0f}個”) print(f”安全在庫: {safety_stock:.0f}個”) print() print(“【運用ルール】”) print(f”・在庫が{reorder_point:.0f}個を下回ったら発注”) print(f”・発注量は{eoq_value:.0f}個”) print(f”・約{365 / (annual_demand / eoq_value):.0f}日ごとに発注”)
# 出力結果 【在庫管理パラメータまとめ】 年間需要: 10,950個 経済的発注量(EOQ): 740個 発注点: 254個 安全在庫: 44個 【運用ルール】 ・在庫が254個を下回ったら発注 ・発注量は740個 ・約25日ごとに発注

Excelでの実装

【Excelで安全在庫と発注点を計算する方法】 ■ データ入力 A列 B列 ──────────────────── 日次平均需要 30 日次需要の標準偏差 10 リードタイム 7 サービス率 0.95 ■ 安全係数(Z値)の計算(B6セル) =NORM.S.INV(B4) 結果:1.65 ※ NORM.S.INV: 標準正規分布の逆関数 サービス率0.95を入れると、Z=1.65が返る ■ 安全在庫の計算(B7セル) =B6*SQRT(B3)*B2 結果:44個 ■ リードタイム需要(B8セル) =B1*B3 結果:210個 ■ 発注点(B9セル) =B8+B7 結果:254個

📊 4. 在庫シミュレーション

シミュレーションの目的

計算で求めたEOQや安全在庫が、実際にうまく機能するかをシミュレーションで確認しましょう。需要のランダムな変動を再現して、欠品が起きるかどうかをテストします。

# ============================================ # 在庫シミュレーション(1年間) # ============================================ np.random.seed(42) # 再現性のため(毎回同じ結果になる) # シミュレーション期間 days = 365 # 日次需要をランダムに生成(正規分布に従う) # np.random.normal(平均, 標準偏差, 個数) daily_demand_sim = np.random.normal(avg_daily_demand, demand_std, days) # 負の需要は0に変換(需要がマイナスになることはない) daily_demand_sim = np.maximum(daily_demand_sim, 0) print(f”シミュレーションの需要統計:”) print(f” 平均需要: {np.mean(daily_demand_sim):.1f}個/日”) print(f” 標準偏差: {np.std(daily_demand_sim):.1f}個”) print(f” 最小需要: {np.min(daily_demand_sim):.1f}個”) print(f” 最大需要: {np.max(daily_demand_sim):.1f}個”)
# 出力結果 シミュレーションの需要統計: 平均需要: 30.2個/日 標準偏差: 9.8個 最小需要: 5.3個 最大需要: 57.1個

Step 2:1年間の在庫推移をシミュレーション

※ 以下のコードは横スクロールで全体を確認できます。

# ============================================ # 1年間の在庫推移シミュレーション # ============================================ # 結果を記録するリスト inventory_levels = [] # 日ごとの在庫量 orders_placed = [] # 発注した日 stockouts = [] # 欠品した個数 # 初期状態 current_inventory = eoq_value # 初期在庫はEOQ分 pending_order = 0 # 発注中の数量 days_until_delivery = 0 # 届くまでの日数 # 1年間(365日)をシミュレーション for day in range(days): # ① 発注品が届くかチェック if days_until_delivery > 0: days_until_delivery -= 1 if days_until_delivery == 0: # 発注品が届いた! current_inventory += pending_order pending_order = 0 # ② 発注点を下回ったら発注 if current_inventory <= reorder_point and pending_order == 0: pending_order = eoq_value # EOQ分を発注 days_until_delivery = lead_time # リードタイム後に届く orders_placed.append(day) # 発注日を記録 # ③ 当日の需要に対応 demand = daily_demand_sim[day] if current_inventory >= demand: # 在庫で対応できた current_inventory -= demand stockouts.append(0) else: # 欠品発生! stockouts.append(demand – current_inventory) current_inventory = 0 # ④ 在庫量を記録 inventory_levels.append(current_inventory) # ============================================ # 結果の集計 # ============================================ total_stockouts = sum(stockouts) stockout_days = sum([1 for s in stockouts if s > 0]) service_rate_actual = (days – stockout_days) / days print(“【シミュレーション結果(1年間)】”) print() print(f”総需要: {sum(daily_demand_sim):.0f}個”) print(f”発注回数: {len(orders_placed)}回”) print(f”欠品日数: {stockout_days}日”) print(f”欠品個数: {total_stockouts:.0f}個”) print(f”実際のサービス率: {service_rate_actual*100:.1f}%”) print(f”目標サービス率: {service_level*100:.0f}%”)
# 出力結果 【シミュレーション結果(1年間)】 総需要: 11,023個 発注回数: 15回 欠品日数: 3日 欠品個数: 28個 実際のサービス率: 99.2% 目標サービス率: 95%
📌 シミュレーション結果の解釈

サービス率の結果
・目標:95%
・実績:99.2%
→ 目標を上回る結果!安全在庫が効果を発揮

欠品の発生
・365日中3日だけ欠品
・欠品個数は28個(年間需要の0.25%)
→ 許容範囲内

※ シミュレーションは毎回結果が変わります(乱数のため)
※ 実際の運用では、定期的に実績を確認して調整します

📝 STEP 38 のまとめ

✅ このステップで学んだこと

1. 在庫管理の基礎

  • 在庫コスト削減と欠品防止のトレードオフ
  • 発注コスト・保管コスト・欠品コストの3つ

2. 経済的発注量(EOQ)

  • EOQ = √(2 × D × S ÷ H)
  • 発注コストと保管コストがバランスする点
  • EOQでは両コストがほぼ等しくなる

3. 安全在庫の設計

  • 安全在庫 = Z × √(リードタイム) × σ
  • サービス率95%なら Z = 1.65
  • 需要の変動に備えるバッファ

4. 発注点(Reorder Point)

  • 発注点 = リードタイム需要 + 安全在庫
  • 在庫が発注点を下回ったら発注
💡 実務での活用ポイント

日次チェック:
在庫が発注点を下回っていないか確認 → 下回ったらEOQ分を発注

週次レビュー:
需要の変動をモニタリング → 標準偏差が変わったら安全在庫を再計算

月次見直し:
サービス率の実績を確認 → 目標に達していなければ安全在庫を増やす

四半期最適化:
需要パターンの変化を確認 → EOQと安全在庫を再計算

🎯 次のステップの予告

STEP 39では、「感度分析とシナリオ分析」を学びます。パラメータが変化したときに結果がどう変わるかを分析する方法を習得しましょう!

📝 練習問題

問題 1 基礎

以下の条件でEOQを計算してください。

・年間需要量:5,000個
・発注コスト:3,000円/回
・保管コスト:150円/個・年

また、EOQで発注した場合の年間発注回数と年間総コストを求めてください。

【解答】

EOQの計算:

EOQ = √(2 × D × S ÷ H)

D = 5,000個
S = 3,000円
H = 150円

EOQ = √(2 × 5,000 × 3,000 ÷ 150)
= √(30,000,000 ÷ 150)
= √200,000
= 447個(約450個)

年間発注回数:

年間発注回数 = D ÷ EOQ
= 5,000 ÷ 447
= 11.2回(約11回)

年間総コスト:

年間発注コスト = 11.2 × 3,000 = 33,600円
年間保管コスト = (447 ÷ 2)× 150 = 33,525円
年間総コスト = 33,600 + 33,525 = 67,125円

※ 発注コストと保管コストがほぼ等しい!
→ EOQが最適であることの証拠
問題 2 基礎

在庫管理の3つのコストについて、それぞれの特徴を説明してください。

【解答】
コストの種類 内容 特徴
発注コスト 発注業務の人件費、運送費、検品費用 発注回数に比例
→ 発注量を増やすと減る
保管コスト 倉庫代、在庫管理費、保険料、金利 在庫量に比例
→ 発注量を増やすと増える
欠品コスト 販売機会損失、緊急発注費用、顧客離れ 在庫が少ないと増加
→ 安全在庫で防ぐ

重要なポイント:
発注コストと保管コストは逆の関係にある。
EOQはこの2つがバランスする点を見つける公式。

問題 3 応用

以下の条件で安全在庫と発注点を計算してください。

・日次平均需要:50個/日
・日次需要の標準偏差:15個
・リードタイム:10日
・サービス率:95%(Z = 1.65)

【解答】

安全在庫の計算:

安全在庫 = Z × √(リードタイム) × σ

Z = 1.65(サービス率95%)
リードタイム = 10日
σ = 15個

安全在庫 = 1.65 × √10 × 15
= 1.65 × 3.16 × 15
= 78個

リードタイム需要:

リードタイム需要 = 日次平均需要 × リードタイム
= 50 × 10
= 500個

発注点:

発注点 = リードタイム需要 + 安全在庫
= 500 + 78
= 578個

運用ルール:
在庫が578個を下回ったら発注する
問題 4 応用

サービス率を95%から99%に上げると、安全在庫はどう変わりますか?

条件:
・リードタイム:7日
・日次需要の標準偏差:10個
・95%のZ値:1.65
・99%のZ値:2.33

【解答】

サービス率95%の場合:

安全在庫 = 1.65 × √7 × 10
= 1.65 × 2.65 × 10
= 44個

サービス率99%の場合:

安全在庫 = 2.33 × √7 × 10
= 2.33 × 2.65 × 10
= 62個

変化量:

増加量 = 62 – 44 = 18個増加
増加率 = 18 ÷ 44 = 約41%増加

ポイント:
サービス率を4%上げるだけで、安全在庫は41%も増える。
→ サービス率を上げるほど、保管コストが急激に増加
→ 商品の重要度に応じて適切なサービス率を設定することが大切
問題 5 実践

ある商品の在庫管理を任されました。以下のデータから、最適な発注量と発注点を提案してください。

・年間需要量:20,000個
・発注コスト:8,000円/回
・保管コスト:400円/個・年
・リードタイム:5日
・日次需要の標準偏差:12個
・目標サービス率:95%(Z = 1.65)

※ 1年 = 365日として計算

【解答】

① EOQの計算:

EOQ = √(2 × 20,000 × 8,000 ÷ 400)
= √(320,000,000 ÷ 400)
= √800,000
= 894個(約900個)

② 日次平均需要:

日次平均需要 = 20,000 ÷ 365
= 55個/日

③ 安全在庫:

安全在庫 = 1.65 × √5 × 12
= 1.65 × 2.24 × 12
= 44個

④ 発注点:

リードタイム需要 = 55 × 5 = 275個
発注点 = 275 + 44 = 319個

⑤ 提案まとめ:

【在庫管理ルール提案】

発注量:900個(毎回この数量を発注)
発注点:319個(この数量を下回ったら発注)
安全在庫:44個(最低限持っておく在庫)

期待される効果:
・年間発注回数:約22回(約16日ごと)
・年間発注コスト:178,000円
・年間保管コスト:178,000円
・年間総コスト:約356,000円
・サービス率:95%(欠品防止)

❓ よくある質問

Q1: EOQの前提条件が現実と合わない場合は?
現実に合わせて修正モデルを使います。

EOQの主な前提:
① 需要は一定 → 実際は変動する
② 単価は一定 → 数量割引がある場合も
③ 一度に入荷 → 分納される場合も

対処法:
・需要変動 → 安全在庫で対応
・数量割引 → 各価格帯でEOQを計算して比較
・分納 → 生産発注量(EPQ)モデルを使用

実務のアドバイス:
完璧なモデルを求めず、80%の精度で十分。現状より改善できればOKです!
Q2: サービス率はどうやって決めればいいですか?
商品の重要度と欠品の影響度で決めます。

ABC分析との組み合わせ:
・Aランク商品(売上の80%)→ サービス率99%
・Bランク商品(次の15%)→ サービス率95%
・Cランク商品(残りの5%)→ サービス率90%

欠品の影響度で決める場合:
・顧客が競合に流れる → 99%
・生産ラインが止まる → 99%
・代替品がある → 90%
・バックオーダー可能 → 90%

推奨:まずは95%からスタートして、実績を見ながら調整しましょう。
Q3: 季節性のある商品はどう管理すれば?
季節ごとにパラメータを変えて管理します。

繁忙期(需要が多い時期):
・EOQを増やす(需要が3倍なら、EOQは√3倍≈1.7倍)
・安全在庫を増やす(変動が大きくなるため)
・サービス率を上げる(欠品の影響が大きい)

閑散期(需要が少ない時期):
・EOQを減らす
・安全在庫も減らす
・在庫の積み増しを控える

事前準備:
繁忙期の1〜2ヶ月前から在庫を積み増し始める。
Q4: ExcelとPython、どちらを使うべき?
状況に応じて使い分けましょう。

Excelが向いている場合:
・少数の商品を管理
・チームで共有したい
・簡単な計算だけでOK
・グラフで視覚化したい

Pythonが向いている場合:
・多数の商品を一括管理
・シミュレーションをしたい
・定期的に自動実行したい
・複雑な分析が必要

おすすめ:
まずExcelで理解 → 本格運用はPythonで自動化
Q5: 需要の標準偏差はどうやって計算する?
過去の販売データから計算します。

Excelの場合:
=STDEV.S(範囲)
例:=STDEV.S(B2:B366) で1年分の日次データから計算

Pythonの場合:
np.std(sales_data, ddof=1)

データがない場合の目安:
・安定した需要 → 平均の10〜20%
・変動が大きい → 平均の30〜50%
・季節商品 → 平均の50%以上

注意:
最低でも3ヶ月分、できれば1年分のデータがあると精度が上がります。
📝

学習メモ

ビジネスデータ分析・意思決定 - Step 38

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE