発注費用と保管費用のバランスから、年間総費用が最小になる発注量(EOQ)を Python で算出します。架空のサンプルデータを用いた計算例では、EOQ は 775個、年間総費用は 154,919円 と求められました。
発注量を決める 2 つの費用
発注量を決める際、考慮すべき費用は主に 2 つあります。1 つは発注費用です。これは発注書作成や検収、輸送に伴う固定的なコストで、発注回数に比例して増加します。もう 1 つは保管費用です。倉庫費や保険、陳腐化リスク、資金コストなどが含まれ、在庫量に比例して増加します。
これらはトレードオフの関係にあります。発注量を増やせば発注回数は減り、発注費用は下がります。しかし、在庫は多くなり、保管費用は上がります。逆に発注量を減らせば保管費用は下がりますが、発注費用は上がります。
この 2 つの費用の合計が最小になる発注量が、経済的発注量(EOQ)です。ウィルソンの公式を用いることで、この最適点を数学的に求めることができます。
EOQ の計算式
経済的発注量(EOQ)は、発注費用と保管費用の合計を最小にする発注量です。計算式は「EOQ = √(2 × 年間需要 × 発注費用 ÷ 単位あたり年間保管費用)」で表されます。ここで、年間需要は一定と仮定し、発注費用は事務処理や検収にかかる固定費、保管費用は倉庫費や資金コストを含みます。
年間総費用は「発注費用 × 発注回数 + 保管費用 × 平均在庫」で求めます。発注回数は年間需要を1回の発注量で割った値です。平均在庫は、一度に納入される前提から、発注量の半分(Q/2)と見なせます。この2つの費用は、発注量が増えると逆の方向に動くため、バランスの取れた点で総費用が最小になります。
本記事の計算例で使用している数値は、乱数で生成した架空のサンプルデータによるものです。実際の業務では、数量割引や最低発注量などの制約があるため、EOQは目安として活用します。(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))
Pythonで EOQ を計算する
ここでは、ウィルソンの公式を用いた経済的発注量(EOQ)の計算を Python で行います。計算例の数値は、乱数で生成した架空のサンプルデータによるものです。
まず、計算ロジックを定義します。
EOQ と年間総費用を計算する関数
import math
def eoq(annual_demand: float, order_cost: float, holding_cost: float) -> float:
"""経済的発注量 = √(2 × 年間需要 × 1回の発注費用 ÷ 1個あたり年間保管費用)。"""
return math.sqrt(2 * annual_demand * order_cost / holding_cost)
def total_cost(q: float, annual_demand: float, order_cost: float, holding_cost: float) -> float:
"""年間総費用 = 発注費用 × 発注回数 + 保管費用 × 平均在庫(Q/2)。"""
return annual_demand / q * order_cost + q / 2 * holding_cost は、年間需要・発注費用・保管費用を入力として受け取り、EOQ を算出します。さらに、年間発注回数・平均在庫量・年間総費用も同時に計算し、結果を返します。
次に、具体的な数値で実行します。
年間需要 12,000 個・発注費用 5,000 円・保管費用 200 円/個/年 で EOQ を計算する
annual_demand, order_cost, holding_cost = 12000, 5000, 200 # 年間12,000個、発注1回5,000円、保管1個あたり年200円
q = eoq(annual_demand, order_cost, holding_cost)
print(f"EOQ = {q:.0f}個")
print(f"年間発注回数 = {annual_demand / q:.1f}回、平均在庫 = {q / 2:.0f}個")
print(f"年間総費用 = {total_cost(q, annual_demand, order_cost, holding_cost):,.0f}円") では、年間需要 12,000個、発注費用 5,000円、保管費用 200円/個/年 を入力しています(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
実行結果として、EOQ は 775個 と算出されました。これにより、年間発注回数は 15.5回、平均在庫量は 387個 となります。年間総費用は 154,919円 です(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
発注量を変えると総費用はどう変わるか
発注量を変えた場合の年間費用を、以下の表にまとめました。
| 発注量 | 発注回数 | 発注費用 | 保管費用 | 総費用 |
|---|---|---|---|---|
| 300個 | 40.0回 | 200,000円 | 30,000円 | 230,000円 |
| 500個 | 24.0回 | 120,000円 | 50,000円 | 170,000円 |
| 775個(EOQ) | 15.5回 | 77,419円 | 77,500円 | 154,919円 |
| 1,000個 | 12.0回 | 60,000円 | 100,000円 | 160,000円 |
| 1,500個 | 8.0回 | 40,000円 | 150,000円 | 190,000円 |
(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))

表と図から、総費用が最小になるのは EOQ の 775個 のときです。このときの総費用は 154,919円 でした(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
EOQ から外れた場合の費用変化を見てみましょう。発注量を 500個 に減らすと、総費用は 170,000円 になります。一方、1,000個 に増やすと 160,000円 となります(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
さらに発注量を 300個 にすると 230,000円、1,500個 にすると 190,000円 と、費用はさらに高くなります(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
これらの数値から、EOQ 付近では総費用が最小になり、EOQ から離れるほど費用が増えることがわかります。また、EOQ から少し外れた場合(500個や1,000個)の費用増加は、大きく外れた場合(300個や1,500個)に比べて緩やかであることが示されています(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
発注費用や保管費用が変わるとどうなるか
発注費用や保管費用の見積もりが変わると、EOQ はどう動くのでしょうか。ウィルソンの公式では、発注費用が 2 倍になると EOQ は √2 倍に、保管費用が 2 倍になると 1/√2 倍になります。
具体的には、発注費用が 2 倍の場合、EOQ は 775個 から 1095個 に変化します。一方、保管費用が 2 倍になると、EOQ は 775個 から 548個 に変化します(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
費用が 2 倍という大きな変化でも、EOQ の変化は 548個 から 1095個 の範囲にとどまります。つまり、費用の見積もりが多少ずれても、EOQ に与える影響は比較的小さいといえます。
実務で使うときの注意点
EOQ の計算には、いくつかの前提条件があります。まず、年間需要が一定で既知であること、購入単価が発注量によらず一定であること、そして発注した数量が一度に納入されることを想定しています。また、発注費用には事務処理や検収などの固定的な費用、保管費用には倉庫費や資金コストなどが含まれます(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
しかし、現実の業務ではこれらの条件が完全に満たされることは稀です。例えば、仕入先から数量割引が得られる場合や、最低発注量が設定されている場合、ケース入数に合わせて発注量を丸めなければならない場合などがあります。こうした制約がある場合、EOQ で算出された数値をそのまま発注量として使うのではなく、あくまで目安として捉えることが重要です。実際の発注量は、これらの現実的な制約を考慮して調整する必要があります。
まとめ
EOQ は、発注費用と保管費用の合計を最小化する発注量です。ウィルソンの公式で算出し、Python で簡単に計算できます。ただし、数量割引や最低発注量がある場合は、結果をあくまで目安として使うのが実務的です。
計算方法と注意
- 前提: 年間需要は一定で既知、購入単価は発注量によらず一定、発注した数量は一度に納入される
- 発注費用には事務処理・検収・輸送の固定的な費用、保管費用には倉庫費・保険・陳腐化・資金コストを含める
- 現実には数量割引、最低発注量、ケース入数による丸めがあるため、EOQ は目安として使う
- 計算例の数値は架空のサンプルデータによるもの
出典
- 本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード)
本記事のコードと数値は、乱数で生成した架空のサンプルデータによる再現可能な計算例です。

