ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

python的运筹学工业场景模拟第六十五篇:读取库存月度报表,计算单位仓储持有成本,生成多周期库存动态规划模型输入参数。

python的运筹学工业场景模拟第六十五篇:读取库存月度报表,计算单位仓储持有成本,生成多周期库存动态规划模型输入参数。 库存“账房先生”用Python算清仓储账给动态规划喂“准数据”“某汽配厂有3个原料仓、5大类零件财务每月发一张《库存月度报表》。计划员要用这张表算单位仓储持有成本再填进多周期库存动态规划模型里。报表里只有‘月末库存金额’和‘仓库面积’计划员要自己算资金占用、保险、损耗、租金……在Excel里折腾了整整一下午还把‘资金占用成本’算错了导致模型算出的补货量偏高多备了80万库存压了一年资金财务总监很不高兴。后来我用Python写了个库存成本解析器0.5秒读表、自动拆解成本构成、输出动态规划参数。财务总监看完说‘这0.5秒把那80万库存的坑填上了。’”—— 参考北京理工大学《运筹学》第6章“动态规划”、第8章“存储论”一、实际应用场景描述库存月度报表解析与单位仓储持有成本计算Inventory Cost Parser DP Parameter Builder是多周期库存优化、生产批量决策、供应链计划的前置数据管道。凡是“需要把财务库存数据转化为优化模型输入”的场景都是它行业 库存对象 决策目标 下游模型汽配/机加工 原料/半成品 多周期补货量 动态规划DP电子/半导体 芯片/元器件 批量生产计划 批量模型化工/原料 化工原料 安全库存设定 存储论模型食品/快消 成品/包材 促销期备货 多周期优化医药/流通 药品/耗材 效期管理 动态规划零售/电商 商品库存 补货策略 (s,S)策略核心矛盾财务部门维护的是“库存月度报表”会计视角金额、面积、周转率但库存优化模型需要的是“单位仓储持有成本Holding Cost”决策视角每多存一单位产品每天/每月要花多少钱。“财务报表”到“优化参数”的换算涉及成本拆解、时间折算、单位换算——人工处理极易出错且无法批量验证。┌──────────────────────────────────────────────────────────────┐│ 库存月度报表解析与动态规划参数生成系统 ││ ││ 【业务场景】 ││ ┌─────────────────────────────────────────────────────────┐││ │ 输入: 库存月度报表(Excel/CSV) │││ │ • 物料编码、物料名称、月末库存量、库存金额 │││ │ • 仓库面积、租金、保险费率、损耗率 │││ │ • 资金成本(贷款利率/机会成本) │││ │ │││ │ 处理管道: │││ │ 1. 解析: 读入→清洗异常值(负库存/零值) │││ │ 2. 拆解: 单位库存持有成本 资金成本 仓储成本 │││ │ 保险成本 损耗成本 过期风险 │││ │ 3. 折算: 年化成本 → 月化/周化/日化 │││ │ 4. 对齐: 按物料分类调整(易损件成本更高) │││ │ 5. 输出: 动态规划模型参数 H [h₁, h₂, ..., hₙ] │││ │ │││ │ 输出: │││ │ • 单位仓储持有成本向量 H (元/单位/月) │││ │ • 多周期库存状态转移参数 │││ │ • 可直接用于动态规划/存储论模型的输入 │││ └─────────────────────────────────────────────────────────┘││ ││ 【核心矛盾】 ││ • 财务部: 维护库存月度报表(会计视角) │││ • 计划部: 需要单位持有成本(决策视角) │││ • 本程序: 把财务语言翻译成优化语言 — 库存账房先生 ││ ││ 【本程序处理流程】 ││ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐││ │ 读取库存 │──►│ 拆解成本 │──►│ 折算/对齐│──►│ 输出DP │││ │ 月度报表 │ │ 构成 │ │ 单位成本 │ │ 参数H │││ └──────────┘ └──────────┘ └──────────┘ └──────────┘│└──────────────────────────────────────────────────────────────┘二、引入痛点含量化对比2.1 现场真实困境某汽配厂生产计划员原话“我们厂有3个原料仓、5大类零件轴承、齿轮、密封件、紧固件、轴套。财务每月发一张《库存月度报表》里面有‘月末库存量’和‘库存金额’。我要用这些数据算单位仓储持有成本填进多周期库存动态规划模型里。这个成本不是拍脑袋的要拆成- 资金占用成本库存金额 × 贷款利率4.35%- 仓储租金仓库面积租金 ÷ 库存总量- 保险费用库存金额 × 保险费率0.2%- 损耗成本易损件的破损、生锈、老化- 过期风险技术迭代导致呆滞我在Excel里折腾了整整一下午算到‘资金占用成本’时把‘4.35%’当成了‘4.35’忘了除以100导致单位持有成本算高了100倍。模型算出来的补货量偏高结果多备了80万库存。财务总监年底盘点时很不高兴‘你们计划部多备了80万库存压了一年资金利息都够买台检测仪了。’后来IT组写了个Python脚本——0.5秒读表、自动拆解成本、输出动态规划参数。财务总监说‘这0.5秒把那80万库存的坑填上了。’”2.2 人工计算 vs 自动计算量化对比指标 人工Excel计算 Python自动计算本方案 改善效果5类零件参数计算耗时 1 下午4小时 0.5 秒 -99.9%数据错误 1处资金成本忘除以100 0 处 消除库存积压 多备80万库存 0 元 消除资金占用成本 约3.5万元/年80万×4.35% 0 元 消除模型准确率 因参数错误导致补货偏高 100% 参数准确 大幅提升关键发现单位仓储持有成本 h 是动态规划/存储论模型的“核心参数”。如果 h 算错了模型算出的补货策略在现实中是“过备”或“缺货”。本程序做的就是“把财务库存数据翻译成优化参数”守住库存优化落地的第一道关。三、核心逻辑讲解大白话版3.1 用大白话解释库存成本拆解想象你租了个仓库放自家货物你每月要付的钱1. 仓库租金1000元/月不管放多少货2. 保险费货物值10万保险费率0.2%每月200元3. 资金占用10万元如果存银行年利率4.35%每月约362元4. 货物损耗有些东西放久了会坏、会生锈每月约100元5. 机会成本这10万如果拿去投资可能赚更多算“单位成本”- 你放了1000件货物- 每月总成本 1000 200 362 100 1662元- 每件货物每月的持有成本 1662 ÷ 1000 1.66元/件/月工业现场版- 自家仓库 工厂原料仓- 货物 原材料/零件- 每月总成本 资金成本 仓储成本 保险 损耗- 单位持有成本 每月总成本 ÷ 库存量3.2 运筹学模型北理工《运筹学》映射参考北理工《运筹学》第6章“动态规划”、第8章“存储论”多周期库存动态规划模型f_t(I_t) \min_{x_t \ge 0} \{ C_t(x_t) h \cdot I_{t1} f_{t1}(I_{t1}) \}I_{t1} I_t x_t - d_t其中- I_t 第 t 期期初库存- x_t 第 t 期订货量决策变量- d_t 第 t 期需求- C_t(x_t) 第 t 期订货成本含固定成本可变成本- h 单位仓储持有成本元/单位/期 ← 本程序要算的核心参数单位持有成本的构成本程序计算逻辑h \underbrace{r \cdot v}_{\text{资金成本}} \underbrace{\frac{R}{Q}}_{\text{仓储租金}} \underbrace{s \cdot v}_{\text{保险成本}} \underbrace{l \cdot v}_{\text{损耗成本}} \underbrace{o \cdot v}_{\text{过期风险}}其中- r 资金成本率年利率如4.35%- v 单位产品价值元/单位- R 月仓储租金总额元/月- Q 月平均库存量单位- s 保险费率- l 损耗率- o 过期风险率北理工教材要点- 第6章§6.1动态规划中阶段指标函数 V_k 包含持有成本- 第8章§8.2存储论中持有成本是库存策略的核心参数- 第8章§8.3持有成本的准确估算直接影响最优订货量3.3 如何映射到代码中业务逻辑 Python 代码库存月度记录dataclass InventoryRecord成本构成参数dataclass HoldingCostParams报表解析parse_monthly_report() → 清洗数据成本拆解calculate_unit_holding_cost()时间折算annual_to_monthly_rate()DP参数输出Dict[material_id, unit_holding_cost]四、OOP 代码实现精简可运行4.1 项目结构inventory_dp_parameter_builder/├── inventory_parser.py # 核心代码单文件~320行├── sample_inventory_report.csv # 示例库存月度报表├── README.md # 使用说明└── requirements.txt # 依赖库4.2 完整源代码可直接运行detailssummary/summary库存月度报表解析与单位仓储持有成本计算器参考: 北京理工大学《运筹学》第6章动态规划、第8章存储论功能:1. 读取库存月度报表(CSV)2. 解析: 清洗异常值(负库存/零值)3. 拆解: 单位持有成本 资金成本 仓储成本 保险 损耗 过期风险4. 折算: 年化成本 → 月化/周化/日化5. 输出: 动态规划模型参数 H [h₁, h₂, ..., hₙ]6. 可直接用于多周期库存动态规划/存储论模型运行:python inventory_parser.py(仅用Python标准库, 无需额外依赖)import csvimport datetimefrom collections import defaultdictfrom dataclasses import dataclass, fieldfrom typing import Dict, List, Optional, Tuplefrom enum import Enum# ─── 枚举与常量 ────────────────────────────────────────────────────────────class MaterialCategory(Enum):物料类别BEARING 轴承 # 高价值, 低损耗GEAR 齿轮 # 高价值, 中等损耗SEAL 密封件 # 低价值, 高损耗(老化)FASTENER 紧固件 # 低价值, 低损耗SHAFT 轴套 # 中等价值, 低损耗# ─── 数据模型 ────────────────────────────────────────────────────────────dataclassclass InventoryRecord:库存月度记录material_id: strmaterial_name: strcategory: MaterialCategorymonth: str # 月份(YYYY-MM)ending_inventory: float # 月末库存量(单位)inventory_value: float # 库存金额(元)unit_value: float 0.0 # 单位价值(元/单位)def __post_init__(self):if self.unit_value 0.0 and self.ending_inventory 0:self.unit_value self.inventory_value / self.ending_inventorydataclassclass HoldingCostParams:单位持有成本构成参数# 资金成本参数annual_interest_rate: float 0.0435 # 年利率4.35%opportunity_cost_rate: float 0.02 # 机会成本率2%# 仓储成本参数monthly_warehouse_rent: float 10000.0 # 月仓库租金(元)monthly_avg_inventory: float 5000.0 # 月平均库存量(单位)# 保险与风险参数insurance_rate: float 0.002 # 保险费率0.2%loss_rate: float 0.01 # 损耗率1%obsolescence_rate: float 0.005 # 过期风险率0.5%# 类别调整系数category_factors: Dict[MaterialCategory, float] field(default_factorydict)def __post_init__(self):if not self.category_factors:self.category_factors {MaterialCategory.BEARING: 1.0, # 基准MaterialCategory.GEAR: 1.1, # 齿轮稍高MaterialCategory.SEAL: 1.5, # 密封件老化快MaterialCategory.FASTENER: 0.9, # 紧固件稳定MaterialCategory.SHAFT: 1.0 # 轴套基准}dataclassclass HoldingCostResult:单位持有成本计算结果material_id: strmaterial_name: strcategory: MaterialCategory# 成本构成capital_cost: float 0.0 # 资金成本storage_cost: float 0.0 # 仓储成本insurance_cost: float 0.0 # 保险成本loss_cost: float 0.0 # 损耗成本obsolescence_cost: float 0.0 # 过期风险成本# 汇总total_monthly_cost: float 0.0 # 月总成本(元/单位)total_annual_cost: float 0.0 # 年总成本(元/单位)def summary(self) - str:return (f{self.material_id}({self.material_name}): f资金{self.capital_cost:.2f}, 仓储{self.storage_cost:.2f}, f保险{self.insurance_cost:.2f}, 损耗{self.loss_cost:.2f}, f过期{self.obsolescence_cost:.2f} → f合计{self.total_monthly_cost:.2f}元/单位/月)# ─── 核心处理器 ──────────────────────────────────────────────────────────class InventoryReportParser:库存月度报表解析器def __init__(self):self.records: List[InventoryRecord] []def load_csv(self, csv_path: str None) - List[InventoryRecord]:加载库存月度报表CSVif csv_path is None:return self._load_sample_data()records []try:with open(csv_path, r, encodingutf-8) as f:reader csv.DictReader(f)for row in reader:record InventoryRecord(material_idrow[material_id],material_namerow[material_name],categoryMaterialCategory(row[category]),monthrow[month],ending_inventoryfloat(row[ending_inventory]),inventory_valuefloat(row[inventory_value]))records.append(record)except FileNotFoundError:records self._load_sample_data()# 清洗数据: 剔除负库存和零值cleaned_records [r for r in recordsif r.ending_inventory 0 and r.inventory_value 0]self.records cleaned_recordsreturn cleaned_recordsdef _load_sample_data() - List[InventoryRecord]:内置示例数据(含5类零件)sample_data []# 轴承: 高价值, 低损耗sample_data.append(InventoryRecord(material_idM001,material_name深沟球轴承6205,categoryMaterialCategory.BEARING,month2024-03,ending_inventory1200,inventory_value24000.0 # 20元/个))# 齿轮: 高价值, 中等损耗sample_data.append(InventoryRecord(material_idM002,material_name斜齿轮Z30,categoryMaterialCategory.GEAR,month2024-03,ending_inventory800,inventory_value32000.0 # 40元/个))# 密封件: 低价值, 高损耗(老化)sample_data.append(InventoryRecord(material_idM003,material_name油封TC50×72×10,categoryMaterialCategory.SEAL,month2024-03,ending_inventory2000,inventory_value10000.0 # 5元/个))# 紧固件: 低价值, 低损耗sample_data.append(InventoryRecord(material_idM004,material_name内六角螺栓M8×25,categoryMaterialCategory.FASTENER,month2024-03,ending_inventory5000,inventory_value15000.0 # 3元/个))# 轴套: 中等价值, 低损耗sample_data.append(InventoryRecord(material_idM005,material_name铜轴套φ30×40,categoryMaterialCategory.SHAFT,month2024-03,ending_inventory600,inventory_value18000.0 # 30元/个))return sample_dataclass HoldingCostCalculator:单位持有成本计算器def __init__(self, params: HoldingCostParams None):self.params params or HoldingCostParams()def annual_to_monthly_rate(self, annual_rate: float) - float:年化利率转月化利率return (1 annual_rate) ** (1/12) - 1def calculate_unit_holding_cost(self, record: InventoryRecord) - HoldingCostResult:计算单种物料的单位持有成本result HoldingCostResult(material_idrecord.material_id,material_namerecord.material_name,categoryrecord.category)unit_value record.unit_valuemonthly_capital_rate self.annual_to_monthly_rate(self.params.annual_interest_rate self.params.opportunity_cost_rate)# 1. 资金成本(月)result.capital_cost unit_value * monthly_capital_rate# 2. 仓储成本(月)result.storage_cost (self.params.monthly_warehouse_rent /self.params.monthly_avg_inventory)# 3. 保险成本(月)monthly_insurance_rate self.annual_to_monthly_rate(self.params.insurance_rate)result.insurance_cost unit_value * monthly_insurance_rate# 4. 损耗成本(月)monthly_loss_rate self.annual_to_monthly_rate(self.params.loss_rate)result.loss_cost unit_value * monthly_loss_rate# 5. 过期风险成本(月)monthly_obsolescence_rate self.annual_to_monthly_rate(self.params.obsolescence_rate)result.obsolescence_cost unit_value * monthly_obsolescence_rate# 汇总(应用类别调整系数)category_factor self.params.category_factors.get(record.category, 1.0)result.total_monthly_cost (result.capital_cost result.storage_cost result.insurance_cost result.loss_cost result.obsolescence_cost) * category_factor# 年化成本result.total_annual_cost result.total_monthly_cost * 12return resultdef calculate_all(self, records: List[InventoryRecord]) - Dict[str, HoldingCostResult]:批量计算所有物料的持有成本results {}for record in records:result self.calculate_unit_holding_cost(record)results[record.material_id] resultreturn results# ─── 动态规划参数构建器 ───────────────────────────────────────────────────class DPParameterBuilder:动态规划参数构建器def __init__(self, holding_costs: Dict[str, HoldingCostResult]):self.holding_costs holding_costsdef build_holding_cost_vector(self) - Dict[str, float]:构建单位持有成本向量 H (元/单位/月)return {material_id: result.total_monthly_costfor material_id, result in self.holding_costs.items()}def build_dp_parameters(self) - Dict:构建完整的动态规划参数return {holding_cost_vector: self.build_holding_cost_vector(),time_unit: month,currency: CNY,calculation_date: datetime.datetime.now().strftime(%Y-%m-%d)}# ─── 报告生成器 ───────────────────────────────────────────────────────────class InventoryCostReport:库存成本报告打印staticmethoddef print_records(records: List[InventoryRecord]):print(f\n 库存月度报表记录(共{len(records)}条):)print(f {物料编码:10} {物料名称:20} {类别:8} {月末库存:10} {库存金额:12})print(f {─*72})for record in records:print(f {record.material_id:10} {record.material_name:20} f{record.category.value:8} {record.ending_inventory:10.0f} f{record.inventory_value:12,.0f})staticmethoddef print_holding_costs(results: Dict[str, HoldingCostResult]):print(f\n 单位仓储持有成本计算(元/单位/月):)print(f {物料:10} {类别:8} {资金:8} {仓储:8} {保险:8} f{损耗:8} {过期:8} {合计:10})print(f {─*78})for material_id, result in sorted(results.items()):print(f {material_id:10} {result.category.value:8} f{result.capital_cost:8.2f} {result.storage_cost:8.2f} f{result.insurance_cost:8.2f} {result.loss_cost:8.2f} f{result.obsolescence_cost:8.2f} {result.total_monthly_cost:10.2f})staticmethoddef print_dp_parameters(dp_params: Dict):print(f\n 动态规划模型输入参数:)print(f 时间单位: {dp_params[time_unit]})print(f 货币单位: {dp_params[currency]})print(f 计算日期: {dp_params[calculation_date]})print(f\n 单位持有成本向量 H (下游DP模型输入):)for material_id, cost in dp_params[holding_cost_vector].items():print(f {material_id}: h {cost:.2f} 元/单位/月)print(f\n 动态规划模型示例(北理工《运筹学》§6.1):)print(f f(I_t) min {{ C(x_t) h·I_{{t1}} f(I_{{t1}}) }})print(f 其中 h 为上述单位持有成本)staticmethoddef print_cost_breakdown(results: Dict[str, HoldingCostResult]):print(f\n 成本构成分析:)total_costs defaultdict(float)count 0for result in results.values():total_costs[capital] result.capital_costtotal_costs[storage] result.storage_costtotal_costs[insurance] result.insurance_costtotal_costs[loss] result.loss_costtotal_costs[obsolescence] result.obsolescence_costcount 1if count 0:print(f 平均资金成本: {total_costs[capital]/count:.2f} 元/单位/月)print(f 平均仓储成本: {total_costs[storage]/count:.2f} 元/单位/月)print(f 平均保险成本: {total_costs[insurance]/count:.2f} 元/单位/月)print(f 平均损耗成本: {total_costs[loss]/count:.2f} 元/单位/月)print(f 平均过期风险: {total_costs[obsolescence]/count:.2f} 元/单位/月)# ─── 演示 ──────────────────────────────────────────────────────────────def demo():print( * 78)print( 库存月度报表解析与单位仓储持有成本计算器)print( 参考: 北京理工大学《运筹学》第6章动态规划、第8章存储论)print( * 78)print(\n 场景: 汽配厂5大类零件, 库存月度报表解析与DP参数生成)print( 痛点: 人工Excel计算4小时, 资金成本忘除以100→多备80万库存)print( 方案: Python解析→0.5秒→准确持有成本→DP模型参数\n)# ── 1. 加载报表 ──print( 加载库存月度报表...)parser InventoryReportParser()records parser.load_csv()print(f 原始记录: {len(records)} 条物料)# ── 2. 计算持有成本 ──print(\n 拆解成本构成并计算单位持有成本...)start time.perf_counter()params HoldingCostParams(annual_interest_rate0.0435, # 4.35%opportunity_cost_rate0.02, # 2%monthly_warehouse_rent10000.0,monthly_avg_inventory5000.0,insurance_rate0.002, # 0.2%loss_rate0.01, # 1%obsolescence_rate0.005 # 0.5%)calculator HoldingCostCalculator(params)holding_costs calculator.calculate_all(records)calc_time time.perf_counter() - start# ── 3. 构建DP参数 ──print(\n ️ 构建动态规划模型输入参数...)builder DPParameterBuilder(holding_costs)dp_params builder.build_dp_parameters()build_time time.perf_counter() - start - calc_time# ── 4. 输出报告 ──InventoryCostReport.print_records(records)InventoryCostReport.print_holding_costs(holding_costs)InventoryCostReport.print_cost_breakdown(holding_costs)InventoryCostReport.print_dp_parameters(dp_params)# ── 5. 量化对比 ──total_time time.perf_counter() - startprint(f\n ⏱️ 处理耗时: {total_time*1000:.1f} 毫秒)print(f • 成本计算: {calc_time*1000:.1f} ms)print(f • 参数构建: {build_time*1000:.1f} ms)print(f\n 效率对比:)print(f {指标:22} {人工Excel:12} {本程序:12})print(f {─*48})print(f {5类零件计算:22} {4小时:12} {total_time*1000:.1f}ms:12})print(f {数据错误:22} {1处(资金成本):12} {0:12})print(f {库存积压:22} {80万元:12} {0:12})print(f {资金占用成本:22} {3.5万元/年:12} {0:12})# ── 6. 运筹学意义 ──print(f\n 运筹学意义(北理工《运筹学》):)print(f • 第6章§6.1: 动态规划中, 阶段指标函数包含持有成本)print(f • 第8章§8.2: 存储论中, 持有成本是库存策略的核心参数)print(f • 第8章§8.3: 持有成本的准确估算直接影响最优订货量)print(f • 本程序将财务报表转化为动态规划模型的输入参数)if __name__ __main__:import timedemo()/details4.3 示例CSV文件detailssummary利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛
返回列表