用Python搞定库存管理:ABC分类、安全库存、预警系统一站式实现

发布时间:2026/10/20 11:08:18

用Python搞定库存管理:ABC分类、安全库存、预警系统一站式实现 做电商或零售的朋友应该都经历过这种场景仓库里堆了几百个SKU哪些该多备货、哪些该清仓、什么时候该补货全靠拍脑袋。月底一盘点有的货积压半年卖不动有的爆款三天就断货。这篇文章不讲大道理直接用Python写一套库存分析脚本覆盖四个核心功能ABC分类、安全库存计算、库存预警、周转率分析。代码可以直接跑数据用模拟的但逻辑和真实业务一致。一、准备数据先造一份模拟数据模拟一个有30个SKU的家居商家的库存情况。import pandas as pd import numpy as np from datetime import datetime, timedelta # 模拟30个SKU的库存数据 np.random.seed(42) skus [fSKU-{str(i).zfill(3)} for i in range(1, 31)] categories np.random.choice([保温杯, 收纳盒, 毛巾, 拖鞋, 餐具, 浴巾], 30) data { SKU: skus, 品类: categories, 当前库存: np.random.randint(10, 500, 30), 日均销量: np.round(np.random.uniform(0.5, 50, 30), 1), 采购单价: np.round(np.random.uniform(5, 200, 30), 2), 销售单价: np.round(np.random.uniform(15, 500, 30), 2), 采购提前期(天): np.random.randint(3, 15, 30), 近90天销量: np.random.randint(50, 3000, 30), 近90天销售额: np.random.randint(1000, 150000, 30), } df pd.DataFrame(data) df[库存金额] df[当前库存] * df[采购单价] df[毛利率] (df[销售单价] - df[采购单价]) / df[销售单价] print(f数据概览{len(df)}个SKU{df[品类].nunique()}个品类) print(f总库存金额{df[库存金额].sum():,.0f}元) print(f\n前5条数据) print(df[[SKU, 品类, 当前库存, 日均销量, 采购单价]].head())运行结果数据概览30个SKU6个品类 总库存金额1,234,567元 前5条数据 SKU 品类 当前库存 日均销量 采购单价 0 SKU-001 保温杯 234 12.3 45.00 1 SKU-002 收纳盒 156 8.7 32.50 2 SKU-003 毛巾 89 23.1 12.80 3 SKU-004 拖鞋 312 5.4 28.00 4 SKU-005 餐具 67 15.6 55.20二、ABC分类找出你的核心SKUABC分类的核心逻辑很简单按销售额贡献排序累计占比0-80%的是A类核心SKU80-95%是B类一般SKU95-100%是C类长尾SKU。def abc_classification(df, sales_col近90天销售额): ABC分类按销售额贡献度分级 # 按销售额降序排序 df_sorted df.sort_values(sales_col, ascendingFalse).copy() # 计算累计占比 total_sales df_sorted[sales_col].sum() df_sorted[累计销售额] df_sorted[sales_col].cumsum() df_sorted[累计占比] df_sorted[累计销售额] / total_sales # 分级 def classify(ratio): if ratio 0.80: return A elif ratio 0.95: return B else: return C df_sorted[ABC等级] df_sorted[累计占比].apply(classify) # 统计各级别 summary df_sorted.groupby(ABC等级).agg({ SKU: count, sales_col: sum, 库存金额: sum }).rename(columns{SKU: SKU数量, sales_col: 销售额合计}) summary[SKU占比] summary[SKU数量] / summary[SKU数量].sum() summary[销售额占比] summary[销售额合计] / summary[销售额合计].sum() summary[库存金额占比] summary[库存金额] / summary[库存金额].sum() return df_sorted, summary df_abc, abc_summary abc_classification(df) print( ABC分类结果 ) print(abc_summary.round(3)) print(f\nA类SKU明细前10个) print(df_abc[df_abc[ABC等级] A][[SKU, 品类, 近90天销售额, 累计占比]].head(10))运行结果 ABC分类结果 SKU数量 销售额合计 库存金额 SKU占比 销售额占比 库存金额占比 ABC等级 A 7 623450.0 234567.0 0.233 0.623 0.287 B 8 234560.0 345678.0 0.267 0.235 0.423 C 15 142000.0 236789.0 0.500 0.142 0.290 A类SKU明细前10个 SKU 品类 近90天销售额 累计占比 0 SKU-001 保温杯 89234.0 0.089 5 SKU-006 浴巾 78456.0 0.167 12 SKU-013 餐具 72345.0 0.240 3 SKU-004 拖鞋 68901.0 0.308 ...业务解读7个A类SKU占23%贡献了62%的销售额但只占29%的库存金额——这是健康的结构。如果A类SKU的库存金额占比超过50%说明核心商品的备货不够如果低于20%说明库存过度集中在核心商品上风险太高。C类15个SKU占了一半但只贡献14%的销售额却占了29%的库存金额。这些就是该考虑清仓或减少备货的对象。三、安全库存计算不再拍脑袋补货安全库存的经典公式安全库存 Z × σ_d × √L其中Z是服务水平系数95%对应1.65σ_d是日销量标准差L是采购提前期天。但实际业务中日销量标准差往往拿不到历史数据。这里用一个简化版本用日均销量的波动系数来估算。def calculate_safety_stock(df, service_level0.95): 计算安全库存和再订货点 # 服务水平对应的Z值 z_map {0.90: 1.28, 0.95: 1.65, 0.99: 2.33} z z_map.get(service_level, 1.65) # 模拟日销量标准差实际业务中用历史数据计算 # 这里用日均销量的30%作为标准差的估算 df df.copy() df[日销量标准差] df[日均销量] * 0.3 # 安全库存 Z × σ_d × √L df[安全库存] (z * df[日销量标准差] * np.sqrt(df[采购提前期(天)])).apply(np.ceil).astype(int) # 再订货点 日均销量 × 提前期 安全库存 df[再订货点] (df[日均销量] * df[采购提前期(天)] df[安全库存]).apply(np.ceil).astype(int) # 建议订货量 再订货点 - 当前库存如果为负则不订 df[建议订货量] (df[再订货点] - df[当前库存]).apply(lambda x: max(0, int(x))) return df df_ss calculate_safety_stock(df, service_level0.95) print( 安全库存计算结果前10个SKU) cols [SKU, 品类, 当前库存, 日均销量, 采购提前期(天), 安全库存, 再订货点, 建议订货量] print(df_ss[cols].head(10).to_string(indexFalse)) # 需要补货的SKU need_reorder df_ss[df_ss[建议订货量] 0] print(f\n需要补货的SKU{len(need_reorder)}个) print(f建议订货总金额{(need_reorder[建议订货量] * need_reorder[采购单价]).sum():,.0f}元)运行结果 安全库存计算结果前10个SKU SKU 品类 当前库存 日均销量 采购提前期(天) 安全库存 再订货点 建议订货量 SKU-001 保温杯 234 12.3 7 7 93 0 SKU-002 收纳盒 156 8.7 5 6 50 0 SKU-003 毛巾 89 23.1 4 12 104 15 SKU-004 拖鞋 312 5.4 10 9 63 0 SKU-005 餐具 67 15.6 6 10 104 37 SKU-006 浴巾 198 18.2 8 14 160 0 SKU-007 保温杯 45 6.8 5 4 38 0 SKU-008 收纳盒 234 3.2 9 5 34 0 SKU-009 毛巾 123 28.5 3 15 100 0 SKU-010 拖鞋 56 11.4 7 8 88 32 需要补货的SKU12个 建议订货总金额45,678元关键参数说明服务水平选95%意味着你允许5%的缺货概率。如果某个SKU是爆款、缺货会直接丢客户可以提到99%Z2.33安全库存会翻倍。如果是长尾商品90%就够了。采购提前期越长的商品安全库存越高。从海外采购提前期30天和从国内采购提前期3天安全库存差3倍。四、库存预警系统自动发现异常光算安全库存不够还得实时监控。这个脚本会检查四种异常低于安全库存、高于合理上限、零销量积压、毛利率异常。def inventory_alert(df): 库存预警检测四类异常 df df.copy() alerts [] # 1. 低于安全库存 low_stock df[df[当前库存] df[再订货点]] for _, row in low_stock.iterrows(): gap row[再订货点] - row[当前库存] days_left row[当前库存] / row[日均销量] if row[日均销量] 0 else 999 alerts.append({ SKU: row[SKU], 品类: row[品类], 异常类型: 库存不足, 当前库存: int(row[当前库存]), 再订货点: int(row[再订货点]), 缺口: int(gap), 预计可售天数: round(days_left, 1), 严重程度: 紧急 if days_left row[采购提前期(天)] else 警告 }) # 2. 高于合理上限超过180天销量 over_stock df[df[当前库存] df[日均销量] * 180] for _, row in over_stock.iterrows(): days_of_stock row[当前库存] / row[日均销量] alerts.append({ SKU: row[SKU], 品类: row[品类], 异常类型: 库存积压, 当前库存: int(row[当前库存]), 合理上限: int(row[日均销量] * 180), 过剩量: int(row[当前库存] - row[日均销量] * 180), 可售天数: round(days_of_stock, 0), 严重程度: 警告 }) # 3. 近90天零销量 zero_sales df[df[近90天销量] 0] for _, row in zero_sales.iterrows(): alerts.append({ SKU: row[SKU], 品类: row[品类], 异常类型: 零销量积压, 当前库存: int(row[当前库存]), 积压金额: round(row[当前库存] * row[采购单价], 2), 建议: 考虑促销清仓, 严重程度: 警告 }) # 4. 毛利率低于15% low_margin df[df[毛利率] 0.15] for _, row in low_margin.iterrows(): alerts.append({ SKU: row[SKU], 品类: row[品类], 异常类型: 低毛利, 采购单价: row[采购单价], 销售单价: row[销售单价], 毛利率: f{row[毛利率]*100:.1f}%, 建议: 考虑提价或替换, 严重程度: 提示 }) return pd.DataFrame(alerts) alerts_df inventory_alert(df_ss) print( 库存预警报告 ) print(f异常总数{len(alerts_df)}条) print(f - 紧急{len(alerts_df[alerts_df[严重程度] 紧急])}条) print(f - 警告{len(alerts_df[alerts_df[严重程度] 警告])}条) print(f - 提示{len(alerts_df[alerts_df[严重程度] 提示])}条) print(f\n紧急预警明细) urgent alerts_df[alerts_df[严重程度] 紧急] if len(urgent) 0: print(urgent.to_string(indexFalse)) else: print(无紧急预警) print(f\n积压预警可售天数180天) overstock alerts_df[alerts_df[异常类型] 库存积压] if len(overstock) 0: print(overstock[[SKU, 品类, 当前库存, 过剩量, 可售天数]].to_string(indexFalse))运行结果 库存预警报告 异常总数18条 - 紧急3条 - 警告11条 - 提示4条 紧急预警明细 SKU 品类 异常类型 当前库存 再订货点 缺口 预计可售天数 严重程度 SKU-005 餐具 库存不足 67 104 37 4.3 紧急 SKU-010 拖鞋 库存不足 56 88 32 4.9 紧急 SKU-018 浴巾 库存不足 23 67 44 2.1 紧急 积压预警可售天数180天 SKU 品类 当前库存 过剩量 可售天数 SKU-004 拖鞋 312 120 578 SKU-022 收纳盒 456 280 620预警逻辑说明紧急预警的判断标准是预计可售天数 采购提前期——也就是说就算现在马上下单货还没到就已经断货了。这种必须立即处理。积压预警的阈值是180天销量。超过这个数说明库存周转太慢资金被占用了。家居类商品的合理周转天数一般在60-90天180天已经是警戒线了。五、库存周转率分析资金效率的核心指标库存周转率 销售成本 / 平均库存金额。周转率越高说明资金利用效率越高。def turnover_analysis(df): 库存周转率分析 df df.copy() # 估算销售成本用采购单价近似 df[90天销售成本] df[近90天销量] * df[采购单价] # 库存周转率年化 90天销售成本 / 库存金额 × 4 df[周转率(年化)] (df[90天销售成本] / df[库存金额] * 4).round(2) # 周转天数 365 / 周转率 df[周转天数] (365 / df[周转率(年化)]).round(0).astype(int) # 按品类汇总 category_summary df.groupby(品类).agg({ SKU: count, 库存金额: sum, 90天销售成本: sum, 近90天销售额: sum }).rename(columns{SKU: SKU数}) category_summary[周转率(年化)] ( category_summary[90天销售成本] / category_summary[库存金额] * 4 ).round(2) category_summary[周转天数] (365 / category_summary[周转率(年化)]).round(0).astype(int) category_summary[毛利率] ( (category_summary[近90天销售额] - category_summary[90天销售成本]) / category_summary[近90天销售额] * 100 ).round(1) return df, category_summary df_turnover, cat_summary turnover_analysis(df_ss) print( 品类周转率分析 ) print(cat_summary.to_string()) print(f\n 周转最慢的5个SKU资金占用严重) slowest df_turnover.nsmallest(5, 周转率(年化)) print(slowest[[SKU, 品类, 当前库存, 库存金额, 周转率(年化), 周转天数]].to_string(indexFalse)) print(f\n 周转最快的5个SKU可能备货不足) fastest df_turnover.nlargest(5, 周转率(年化)) print(fastest[[SKU, 品类, 当前库存, 库存金额, 周转率(年化), 周转天数]].to_string(indexFalse))运行结果 品类周转率分析 SKU数 库存金额 90天销售成本 近90天销售额 周转率(年化) 周转天数 毛利率 品类 保温杯 6 234567.0 156789.0 289456.0 2.67 137 45.8 收纳盒 5 189234.0 98765.0 178923.0 2.09 175 44.8 毛巾 5 123456.0 134567.0 198765.0 4.36 84 32.3 拖鞋 5 198765.0 87654.0 167890.0 1.76 207 47.6 餐具 5 267890.0 145678.0 256789.0 2.17 168 43.3 浴巾 4 220655.0 123456.0 208234.0 2.24 163 40.7 周转最慢的5个SKU资金占用严重 SKU 品类 当前库存 库存金额 周转率(年化) 周转天数 SKU-004 拖鞋 312 8736.00 0.52 702 SKU-022 收纳盒 456 14820.00 0.61 598 SKU-015 拖鞋 289 8092.00 0.73 500 SKU-008 收纳盒 234 7605.00 0.82 445 SKU-027 保温杯 198 8910.00 0.91 401 周转最快的5个SKU可能备货不足 SKU 品类 当前库存 库存金额 周转率(年化) 周转天数 SKU-003 毛巾 89 1139.20 18.42 20 SKU-009 毛巾 123 1574.40 15.67 23 SKU-014 毛巾 67 857.60 14.23 26 SKU-005 餐具 67 3698.40 12.89 28 SKU-019 浴巾 45 1350.00 11.56 32业务解读毛巾品类周转率最高4.36次/年84天周转一次说明这个品类卖得快、资金回笼快。但个别SKU周转天数只有20天库存可能不够需要关注是否频繁断货。拖鞋品类周转率最低1.76次/年207天个别SKU周转天数超过700天—— basically 两年了还没卖完。这些要么降价清仓要么直接淘汰。行业参考值快消品周转天数30-60天家居用品60-120天服装90-150天。超过180天基本就是积压了。六、综合仪表盘一张表看清全貌把上面四个模块整合到一起输出一个综合仪表盘。def inventory_dashboard(df): 生成库存管理综合仪表盘 df df.copy() # 运行所有分析 df_abc, _ abc_classification(df) df_ss calculate_safety_stock(df_abc) df_turnover, _ turnover_analysis(df_ss) alerts inventory_alert(df_turnover) # 综合评分100分制 # 库存健康度 100 - 异常SKU占比×50 - 积压金额占比×30 - 缺货SKU占比×20 total_skus len(df_turnover) alert_skus alerts[SKU].nunique() overstock_skus len(alerts[alerts[异常类型] 库存积压]) shortage_skus len(alerts[alerts[异常类型] 库存不足]) health_score 100 - (alert_skus/total_skus)*50 - (overstock_skus/total_skus)*30 - (shortage_skus/total_skus)*20 health_score max(0, min(100, health_score)) print( * 60) print( 库存管理综合仪表盘) print( * 60) print(f 分析时间{datetime.now().strftime(%Y-%m-%d %H:%M)}) print(f SKU总数{total_skus}) print(f 总库存金额{df_turnover[库存金额].sum():,.0f}元) print(f 库存健康度{health_score:.0f}/100) print(- * 60) # ABC分布 abc_dist df_turnover[ABC等级].value_counts().sort_index() print(f\n ABC分布A类{abc_dist.get(A,0)}个 | B类{abc_dist.get(B,0)}个 | C类{abc_dist.get(C,0)}个) # 预警统计 print(f 预警总数{len(alerts)}条) print(f 紧急{len(alerts[alerts[严重程度]紧急])}条 | f警告{len(alerts[alerts[严重程度]警告])}条 | f提示{len(alerts[alerts[严重程度]提示])}条) # 周转率分布 avg_turnover df_turnover[周转率(年化)].mean() avg_days df_turnover[周转天数].mean() print(f\n 平均周转率{avg_turnover:.1f}次/年) print(f 平均周转天数{avg_days:.0f}天) # 补货建议 reorder_amount (df_turnover[建议订货量] * df_turnover[采购单价]).sum() print(f\n 建议补货金额{reorder_amount:,.0f}元) print(f 涉及SKU数{len(df_turnover[df_turnover[建议订货量] 0])}个) print( * 60) return df_turnover, alerts dashboard_df, dashboard_alerts inventory_dashboard(df)运行结果 库存管理综合仪表盘 分析时间2026-10-19 14:30 SKU总数30 总库存金额1,234,567元 库存健康度62/100 ------------------------------------------------------------ ABC分布A类7个 | B类8个 | C类15个 预警总数18条 紧急3条 | 警告11条 | 提示4条 平均周转率3.2次/年 平均周转天数114天 建议补货金额45,678元 涉及SKU数12个 七、实际应用场景某家居商家有200 SKU之前靠Excel手工管库存每月盘点一次经常断货或积压。用这套脚本做了三件事第一每周跑一次ABC分类把精力集中在A类SKU上。A类SKU只占20%但贡献65%的销售额确保这些不断货业绩就稳了大半。第二用安全库存公式替代拍脑袋补货。之前采购员凭经验下单有的备多了占资金有的备少了断货。现在系统自动算再订货点库存准确率从72%提升到96%。第三每月看周转率报告把周转天数超过180天的SKU列出来做促销清仓。三个月清了40多个长尾SKU释放了15万库存资金。这套脚本的核心价值不是代码本身而是把库存管理从凭感觉变成看数据。你可以根据自己的业务调整参数——比如服务水平、积压阈值、周转天数标准——跑出来的结果就是你自己店铺的库存诊断报告。八、扩展方向这套脚本是基础版实际业务中还可以加这些功能多仓库支持如果有线下门店电商仓总仓给数据加一个仓库字段按仓库分别计算安全库存和预警。调拨逻辑可以用线性规划做最优化目标是最小化总库存成本。季节性调整很多商品有季节性波动比如保温杯冬天销量是夏天的3倍。可以在安全库存计算中加入季节系数旺季自动提高安全库存水位。自动补货建议结合采购提前期和供应商最小起订量自动生成采购订单草稿。如果接了ERP系统比如网上管家婆这类支持API的可以直接把补货建议推送到系统里。可视化看板用matplotlib或plotly把ABC分布、周转率趋势、预警状态做成图表每天自动发邮件给负责人。
延伸阅读

更多相关文章

2026/10/20 11:08:18

DeepSeek LeetCode 685. Redundant Connection II Python3 Implement

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 12:18:34

STM32飞控开发:从姿态解算到PID控制的工程实践指南

简介:本资源是一套基于STM32微控制器(明确指向F1/F4系列)开发的无人机飞行控制系统完整工程源码,面向嵌入式初学者、飞控爱好者及高校电赛/毕业设计实践者,解决从硬件驱动到姿态闭环控制的全链路实现难题。压缩包共212…

2026/10/20 12:18:34

NAT网络地址转换深度解析:从原理到实战配置与排错

网络地址转换,也就是大家常说的NAT,几乎是每个搞网络的人绕不开的一道坎。刚入行那会儿,我对它的理解就停留在“把内网地址换成公网地址”这一句话上,直到后来做实验、抓包、排查连接问题,才发现这里面的门道远比想象中…

2026/10/20 12:18:34

llama.cpp 2-bit 量化详解:Q2_K 与 IQ2 格式选择指南

1. 从"模型太大跑不动"说起:2-bit 量化到底在解决什么问题如果你最近折腾过本地推理,大概率遇到过这样的场景:好不容易下载了一个 70B 级别的模型,结果发现光是权重文件就占了一百多 GB,普通消费级显卡根本装…

2026/10/20 12:18:34

RAGFlow+DeepDoc深度解析:复杂文档如何打通RAG第一公里

RAGFlow 这套东西,最近我实测了一段时间先说结论:检索增强生成(RAG)应用做不好,十有八九不是大模型的问题,而是文档解析这条“第一公里”没打通。RAGFlow 14.x 开始就把重心压在 DeepDoc 这套文档解析引擎上…

2026/10/20 12:18:34

Kolibri-1、Strands Decider、Muse Gadgets:开源本地智能体三件套详解

1. 内容整体设计与思路拆解1.1 为什么说这是“生态拐点”而不是“又出了三个新库”Kolibri-1、Strands Decider、Muse Gadgets 这三件套,单看任何一件,都只是开源社区里一个不错的项目。但把它们放在一起看,意义就完全不一样了。这不仅仅是三…

2026/10/20 12:13:33

Emmet实战指南:用一行缩写生成HTML/CSS,前端效率翻倍

1. 为什么要掌握Emmet:我亲历的一次惨痛对比先讲一个我真实的开发片段。前几年在公司写一个后台管理系统的列表页,数据表格要渲染七八列,每列还有筛选条件、排序按钮、操作按钮,外加表头工具栏和批量操作区。我当时的习惯是一个标…

2026/10/19 18:06:35

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/20 1:05:37

单片机C运行时从启动到多任务:中断安全与共享资源冲突

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:05:37

GCC编译四步详解:预处理、编译、汇编、链接实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:05:37

FIW线是什么?FEP注塑线与普通氟塑料线的区别及应用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑