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 点位于两条成本曲线的交点处。

EOQ 成本结构图:订货批量 vs 年成本 订货批量 Q (件) 0 500 707 (EOQ) 年成本 (元) 总成本 持有成本 订货成本 EOQ 最低总成本点 说明:在 EOQ 点(707 件)处,订货成本与持有成本相等,总成本达到最小值 16,970.56 元。

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%,建议与供应商协商调整最小起订量或包装规格,或重新评估持有成本参数。