ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Python库存优化实战:需求预测与自动补货计划

Python库存优化实战:需求预测与自动补货计划 简介面向库存管理与需求预测场景的Python源码包适合供应链、数据分析以及有一定Python基础的算法学习者使用重点解决库存优化、需求预测、数据清洗与系统对接等实际问题。包内共21个文件以6个py脚本为算法核心配合5个xlsx工作表、2个csv数据文件、2个png趋势图以及md/xml/txt等说明配置内容压缩后约10.45MB结构清晰便于按模块阅读和复用其中Markdown文档和Git配置也为二次开发与版本管理提供了便利。当前已有411人学习浏览。资源不仅提供需求预测与库存补充的核心代码还覆盖Excel数据预处理、预测结果落表、库存趋势可视化等完整处理链路通过源码、示例数据与项目说明读者可以理解从历史数据清洗、模型构建到生成补货计划的实现过程并据此扩展到制造业、零售业或电商场景的库存管理实践。1. 库存优化与需求预测从表格到决策如果手头只有一堆Excel和几个Python脚本你会怎么处理库存优化我在拆解这个项目时最先看到的是文件清单里这样一组东西inventory.xlsx、product_price.xlsx、prediction.xlsx以及六个以xlsxtosql.py结尾的脚本和两个process*.py。它们组合起来的路径很明确先把散落在数据表里的库存、价格和历史销量搬进库再用算法预测未来需求最后生成补货计划。这套做法适合手里有历史销售数据、却还靠手动调库存的团队也适合想用Python快速验证预测思路的从业者。库存管理的核心其实不是多囤货而是在需求波动下平衡缺货和积压。解决它需要三步干净的数据、靠谱的预测、可执行的补货规则。下面按这三步展开。2. Excel转SQL把库存和价格数据搬进SQLite任何预测模型都建立在可查询的数据上。项目里inventoryxlsxtosql.py和product_pricexlsxtosql.py这类脚本做的就是同一件事把Excel工作表转成结构化表。我一般会用SQLite做轻量落库因为它不需要搭建独立数据库服务一个文件就能跑完整个流程适合算法原型和中小规模项目。2.1 读取Excel并清洗字段用pandas读取inventory.xlsx注意Excel里常见的坑表头不在第一行、空行、日期被读成float、金额带货币符号。先把这些处理掉再写库。import pandas as pd import sqlite3 def excel_to_sqlite(excel_path, sheet_name, table_name, conn): df pd.read_excel(excel_path, sheet_namesheet_name, header0) # 删除全空行和全空列 df.dropna(howall, inplaceTrue) df.dropna(axis1, howall, inplaceTrue) # 规范列名去空格、转小写 df.columns [c.strip().lower().replace( , _) for c in df.columns] # 日期字段统一成字符串避免SQLite写入类型报错 for col in df.select_dtypes(include[datetime64[ns]]).columns: df[col] df[col].dt.strftime(%Y-%m-%d) df.to_sql(table_name, conn, if_existsreplace, indexFalse) print(f{table_name}: {len(df)} rows) return df if __name__ __main__: conn sqlite3.connect(inventory.db) excel_to_sqlite(inventory.xlsx, 库存表, inventory, conn) excel_to_sqlite(product_price.xlsx, 价格表, product_price, conn) excel_to_sqlite(prediction.xlsx, 预测表, prediction, conn) conn.close()逻辑说明dropna(howall)去掉全空行select_dtypes(include[datetime64[ns]])确保只有日期列做格式化避免把普通数字列也转字符串。if_existsreplace在原型阶段很有用重复跑不会重复插入。参数上sheet_name可以传工作表名或索引位置如果文件里有多个分表建议显式传名字。以上代码能应付大多数中小数据量如果Excel超过几十万行可以考虑按块读取并分批to_sql但项目里这些工作表通常不会那么大。2.2 用CSV桥接不同环节replenishment_plan.csv和filtered_replenishment_plan.csv说明流程里用CSV做中间产物。这比直接改Excel更稳妥因为CSV没有公式和合并单元格各脚本之间传递数据结构一致。从SQLite导出预测结果到CSV也很简单sqlite3 -header -csv inventory.db select * from prediction; prediction_export.csv为什么不直接用Excel给下一步Excel在人工看的时候好用但跨脚本传参时它的格式问题会放大日期序列号、科学计数法、合并单元格都会导致读数和预期不一致。CSV是中间层的通用语言。下面这张表归纳了项目中三类文件的用途文件内容在流程中的角色inventory.xlsx现有库存量、安全库存、仓库信息基础库存数据product_price.xlsx产品单价、成本价用于计算补货金额和库存价值prediction.xlsx历史销量、预测结果算法输入/输出replenishment_plan.csvSKU、补货数量、建议时间最终补货决策处理完数据之后下一步才是需求预测。所以别急着调模型先保证每次跑出来的数据是干净、可复现的。3. 需求预测指数平滑与趋势基线process.py和process2.py承担了核心计算。需求预测这里项目没有指定具体模型按常见的企业库存场景我倾向于先用指数平滑打底因为它参数少、可解释性强并且能直接给出下一周期的预测值。相比ARIMA和神经网络指数平滑对数据量要求低几百天的历史数据就能稳定运行。3.1 简单指数平滑实现给定历史销量序列y_1, ..., y_t指数平滑的递推式是S_t alpha * y_t (1 - alpha) * S_{t-1}其中S_t是当前平滑值alpha在0到1之间。预测下一期时直接用最后一个S_t作为未来各期的均值预测。alpha越大模型对近期变化越敏感alpha越小序列越平滑。代码实现import numpy as np import pandas as pd def simple_exponential_smoothing(series, alpha): series np.asarray(series, dtypefloat) s np.zeros_like(series) s[0] series[0] for i in range(1, len(series)): s[i] alpha * series[i] (1 - alpha) * s[i-1] return s # 示例读取历史销量并预测未来 df pd.read_csv(sales_history.csv, parse_dates[date]) daily df.groupby(date)[qty].sum().sort_index() alpha 0.3 smoothed simple_exponential_smoothing(daily.values, alpha) next_forecast smoothed[-1] print(falpha{alpha}, 下一期预测值{next_forecast:.1f})逻辑说明序列第一个值没有历史所以直接用series[0]作为初始值这是最常用的初始化方式。更稳妥的是用前几期平均值做初始平滑值但在数据量大时差别不大。alpha选0.3是比较保守的默认值适合需求波动小的品类。实际调参要看预测误差。3.2 alpha怎么选不要手动乱调alpha用网格搜索加交叉验证。把历史数据切成训练集和验证集对每个候选alpha计算均方误差MSE或平均绝对误差MAE选最小的那个。下表列出几个alpha取值在不同波动场景下的表现方向供参考alpha适用场景风险0.1~0.2需求稳定、趋势平缓对突变反应慢0.3~0.5需求有短期波动、但整体平稳中等灵敏度0.6~0.8促销季、节假日效应明显容易过拟合噪声如果选中更大的alpha观察下一期实际值是否频繁超预测区间是则说明过拟合回到0.3附近重新验。另一个常见做法是同时计算Holt线性趋势模型把趋势项b_t也平滑掉这时用process.py里的遗留逻辑扩展即可。不过项目源码里这两个process脚本的差异我推测一个是纯平滑、一个叠加了趋势项或周期项具体看输出的中间文件。4. 库存优化安全库存与补货计划生成预测出来的是未来需要多少货但库存优化还要回答现在该补多少、什么时候补。这一步用到从预测结果到replenishment_plan.csv的转化。核心公式是安全库存和订货点SS z * sigma_d * sqrt(L)ROP d_bar * L SS其中z是服务水平对应的标准正态分位数95%服务水平约1.65sigma_d是日需求标准差L是供应商提前期天d_bar是日均需求。当前库存低于ROP时就触发补货补货量由目标库存上限决定。4.1 生成补货计划把预测结果和库存表join起来逐SKU计算补货建议如果现有库存低于ROP就补到目标库存水平否则补货量为0。写CSV作为最终输出。import pandas as pd import numpy as np def generate_replenishment(inventory_df, forecast_df, lead_time_days7, service_level0.95): z 1.645 if service_level 0.95 else 2.33 # 95%或99% merged inventory_df.merge(forecast_df, onsku, howleft) merged[demand_std] merged[history_qty].rolling(30).std() merged[daily_demand] merged[forecast_qty] / 30 merged[safety_stock] z * merged[demand_std] * np.sqrt(lead_time_days) merged[rop] merged[daily_demand] * lead_time_days merged[safety_stock] merged[suggested_order] np.maximum( merged[target_stock] - merged[current_stock], 0 ) merged.loc[merged[current_stock] merged[rop], suggested_order] 0 return merged[[sku, current_stock, rop, safety_stock, suggested_order]] inventory pd.read_csv(inventory_clean.csv) forecast pd.read_csv(forecast_output.csv) plan generate_replenishment(inventory, forecast) plan.to_csv(replenishment_plan.csv, indexFalse)逻辑说明demand_std用30天滚动窗口计算目的是让标准差跟随近期波动变化而不是用全部历史平均。forecast_qty是未来30天的预测总量除以30得到日均需求。target_stock要由人工维护这里假设inventory表里有该字段如果没有可以用daily_demand * (lead_time review_period) safety_stock推算出来。几点注意np.maximum保证补货量不为负。如果现有库存已经高于ROP就强制把补货量设为0避免过度补货。这里写的rolling(30).std()会丢掉前29行所以对短历史数据要在前面填充或改用expanding窗口。4.2 审视filtered_replenishment_plan.csv项目里还有一个filtered_replenishment_plan.csv我的理解是过滤后的补货计划。常见过滤条件是剔除零补货量的SKU、保留需要重点关注的TOP N或是排除长期销量为0的滞销品。过滤逻辑本身不复杂plan pd.read_csv(replenishment_plan.csv) filtered plan[plan[suggested_order] 0].sort_values(suggested_order, ascendingFalse) filtered.to_csv(filtered_replenishment_plan.csv, indexFalse)这一步的意义在于减少采购和仓库人员的信息噪音。原始计划表可能几百行但真正需要当天处理的只有几十行。5. 把流程串起来验证预测效果与排错最后的阶段不是收尾而是把脚本组织成一条可重复执行的流水线并检查预测质量。这里给出一个我常用的落地顺序以及几个最容易栽的坑。5.1 串起脚本调用顺序项目里xlsxtosql.py、process.py、process2.py之间没有直接耦合所以用一个shell命令依次执行即可python inventoryxlsxtosql.py python product_pricexlsxtosql.py python predictionxlsxtosql.py python process.py python process2.py按数据流看前三个脚本把Excel导入SQLite后两个脚本从库中读数据、做预测和补货计算最后输出CSV。为这组命令写一个Makefile或batch会更省事但不改项目结构也行只要保证每次执行顺序一致。5.2 验证预测的误差指标生产环境里没人关心预测曲线长得多好看更在意下一步补货量是否靠谱。因此我建议在process.py里加一段误差输出from sklearn.metrics import mean_absolute_error # 假设有历史验证数据 actual np.array([120, 135, 128]) forecast np.array([118, 132, 125]) mae mean_absolute_error(actual, forecast) print(MAE:, mae) print(误差率: {:.2%}.format(mae / np.mean(actual)))误差率低于15%算基本可用高于30%就要回头检查数据清洗和alpha选择。常见问题出在Excel日期列被识别成文本导致groupby日期后序列断裂预测值长期跳变。碰到这种情况在2.1的read_excel里加parse_dates[date]参数即可。5.3 几个容易踩的边角问题xlsxtosql.py里如果使用openpyxl读取.xlsx要注意加密文件会直接失败~$prediction.xlsx这类临时文件是Excel打开时产生的隐藏缓存检测到要跳过否则读取会报权限错误。CSV文件的编码Windows下保存历史数据时常用GBK但pandas默认UTF-8所以在读取时建议显式指定encodingutf-8或gbk避免读取乱码把预测模型带偏。最后一个小技巧把安全库存的z值做成配置项而不是硬编码这样每个品类可以设置不同的服务水平。这也许只是项目里一个小改动但对库存优化落地而言往往比换更复杂的预测模型更管用。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进