4. EOQ 模型配置实战:使用 Python 计算 EOQ、年订货次数、年总成本
在掌握了 EOQ 模型的理论公式与参数敏感性之后,本节将进入实战环节。我们将使用 Python 语言,将 EOQ 模型从数学公式转化为可执行的工程代码,并基于一组典型参数,计算经济订货批量、年订货次数以及年总成本。
4.1 模型参数定义与输入
在编写代码之前,首先需要明确 EOQ 模型所需的四个核心参数。以下表格列出了本次实战使用的基准数据:
| 参数符号 | 参数名称 | 单位 | 基准值 | 说明 |
|---|---|---|---|---|
| D | 年需求量 | 件/年 | 12,000 | 全年总需求数量 |
| S | 单次订货成本 | 元/次 | 500 | 每次下单产生的固定费用 |
| H | 单位年持有成本 | 元/件·年 | 24 | 每件库存持有一年产生的费用 |
| LT | 订货提前期 | 天 | 7 | 从下单到到货的时间(用于后续安全库存计算) |
实战提示: 在实际工程中,参数 D 应基于历史销售数据与预测模型得出;S 需包含采购、质检、运输协调等全流程费用;H 则需考虑资金占用成本、仓储租金、损耗率等。切勿直接使用经验值,应通过财务与运营数据校准。
4.2 Python 代码实现:核心计算函数
以下代码实现了 EOQ 模型的核心计算逻辑,包括经济订货批量、年订货次数、年订货成本、年持有成本及年总成本。代码采用函数式封装,便于后续集成到库存优化系统中。
import math
def eoq_core(D, S, H):
"""
计算 EOQ 模型核心指标
:param D: 年需求量 (件)
:param S: 单次订货成本 (元)
:param H: 单位年持有成本 (元/件·年)
:return: 包含 EOQ、年订货次数、年总成本的字典
"""
# 1. 计算经济订货批量 (EOQ)
EOQ = math.sqrt((2 * D * S) / H)
# 2. 计算年订货次数
N = D / EOQ
# 3. 计算年订货成本
annual_ordering_cost = (D / EOQ) * S
# 4. 计算年持有成本
annual_holding_cost = (EOQ / 2) * H
# 5. 计算年总成本 (TAC)
TAC = annual_ordering_cost + annual_holding_cost
return {
"EOQ": round(EOQ, 2),
"年订货次数": round(N, 2),
"年订货成本": round(annual_ordering_cost, 2),
"年持有成本": round(annual_holding_cost, 2),
"年总成本": round(TAC, 2)
}
# 使用基准参数执行计算
params = {"D": 12000, "S": 500, "H": 24}
result = eoq_core(**params)
print("=== EOQ 模型计算结果 ===")
for key, value in result.items():
print(f"{key}: {value}")
4.3 计算结果与工程解读
运行上述代码后,得到以下输出结果:
| 指标 | 计算结果 | 工程解读 |
|---|---|---|
| EOQ | 707.11 件 | 每次最优订货数量约为 707 件,低于此值会增加订货频率,高于此值会推高持有成本 |
| 年订货次数 | 16.97 次 | 全年需订货约 17 次,平均每 21.5 天订货一次 |
| 年订货成本 | 8,485.28 元 | 全年因下单产生的固定费用 |
| 年持有成本 | 8,485.28 元 | 全年因持有库存产生的费用,与订货成本相等,验证了 EOQ 模型的平衡特性 |
| 年总成本 | 16,970.56 元 | 在 EOQ 点下,总成本达到理论最小值 |
关键验证: 在 EOQ 最优解处,年订货成本与年持有成本严格相等(均为 8,485.28 元)。这是 EOQ 模型的核心特征——当两种边际成本相等时,总成本达到最低。如果实际计算中两者偏差超过 5%,应检查参数输入或代码逻辑。
4.4 EOQ 成本结构可视化
为了更直观地理解 EOQ 模型的成本平衡机制,下图展示了订货成本、持有成本与总成本随订货批量变化的趋势。EOQ 点位于两条成本曲线的交点处。
4.5 敏感性分析:参数变化对 EOQ 的影响
在实际工程中,参数往往存在波动。以下表格展示了当各参数分别变化 ±20% 时,EOQ 与年总成本的变化幅度,帮助工程师识别关键敏感参数。
| 变化场景 | 参数变化 | EOQ (件) | EOQ 变化率 | 年总成本 (元) | 总成本变化率 |
|---|---|---|---|---|---|
| 基准 | — | 707.11 | — | 16,970.56 | — |
| 需求上升 | D +20% | 774.60 | +9.5% | 18,590.39 | +9.5% |
| 需求下降 | D -20% | 632.46 | -10.6% | 15,198.68 | -10.4% |
| 订货成本上升 | S +20% | 774.60 | +9.5% | 18,590.39 | +9.5% |
| 持有成本上升 | H +20% | 645.50 | -8.7% | 18,590.39 | +9.5% |
工程警示: 从敏感性分析可以看出,年总成本对参数变化的响应是非对称的。持有成本上升 20% 会导致 EOQ 下降 8.7%,但总成本仍上升 9.5%。这意味着在成本控制中,降低持有成本(如优化仓储效率、减少资金占用) 比单纯调整订货批量更有效。切勿盲目追求 EOQ 数值的精确性,而应关注参数本身的准确性。
4.6 代码扩展:批量取整与约束处理
在实际采购中,订货批量往往受到供应商最小起订量、包装规格或运输容量的约束。以下代码展示了如何在 EOQ 基础上进行取整与约束适配:
def eoq_with_constraints(D, S, H, min_order=500, lot_size=50):
"""
带约束的 EOQ 计算
:param min_order: 最小起订量
:param lot_size: 包装规格(批量倍数)
:return: 调整后的 EOQ 及成本
"""
base_eoq = math.sqrt((2 * D * S) / H)
# 向上取整到最近的包装规格倍数
adjusted_eoq = math.ceil(base_eoq / lot_size) * lot_size
# 确保不低于最小起订量
if adjusted_eoq < min_order:
adjusted_eoq = min_order
# 重新计算成本
N = D / adjusted_eoq
annual_ordering_cost = N * S
annual_holding_cost = (adjusted_eoq / 2) * H
TAC = annual_ordering_cost + annual_holding_cost
return {
"理论 EOQ": round(base_eoq, 2),
"实际订货批量": adjusted_eoq,
"年订货次数": round(N, 2),
"年总成本": round(TAC, 2),
"成本增幅": f"{round((TAC - (math.sqrt(2*D*S*H))) / (math.sqrt(2*D*S*H)) * 100, 2)}%"
}
# 示例:最小起订量 600,包装规格 100
constrained_result = eoq_with_constraints(12000, 500, 24, min_order=600, lot_size=100)
print(constrained_result)
实战建议: 当约束条件导致实际订货批量偏离理论 EOQ 时,年总成本的增幅通常控制在 2%-5% 以内。如果增幅超过 10%,建议与供应商协商调整最小起订量或包装规格,或重新评估持有成本参数。