核心目标是:基于完整的过往数据,实现对每一个日期、每个仓库、每种商品所处运营状态的自动化识别,生成可用于补货决策、新品评估及陈列优化的状态标签体系。
date
日期(自然日)
warehouse_id
仓库 ID
sku_id
商品 ID
cate_1 / cate_2 / cate_3
一级/二级/三级品类分类(便于后续按品类动态设定判断阈值)
inventory_qty
当日期末库存数量(或日均库存量)
outbound_qty
当日总出库量(所有门店出库之和)
outbound_store_cnt
当日产生出库行为的门店数(去重统计)
(可选字段)
inbound_qty
当日入库总量
若缺少直接的入库数据
inbound_qty,可通过库存变动与出库数据间接推算。
(warehouse_id, sku_id, date)。
多级品类信息(cate_1/2/3)不改变分析粒度,主要用于差异化配置规则参数——不同品类的商品生命周期、周转频率存在差异,需据此调整判断标准。
在进行状态标注前,需预先计算一系列滑动窗口指标和统计特征,用于检测异常模式或显著变化。
inbound_qty时,可通过库存差额与出库数据估算“隐式入库量”:
inbound_qty(t) = max( inventory_qty(t) - inventory_qty(t-1) + outbound_qty(t), 0 )
公式解释:
库存变化 = 昨日库存 + 入库 - 出库
整理可得:入库 = 当日库存 - 昨日库存 + 当日出库
为避免噪声干扰造成负值,所有计算结果中小于0的“入库量”统一截断为0。
此步骤有助于捕捉新品铺货阶段出现的大规模集中入库现象。
(warehouse_id, sku_id)序列,按时间顺序计算以下滚动指标:
短期动销表现
roll_7d_outbound_qty 最近7日累计出库量
roll_7d_outbound_store_cnt 最近7日内有出库行为的门店总数(每日去重后累加)
中长期销售趋势
roll_30d_outbound_qty 最近30日累计出库量
roll_30d_outbound_store_cnt 最近30日内有出库门店数之和
库存与补货相关指标
roll_7d_inbound_qty 近7日累计入库量
roll_30d_inbound_qty 近30日累计入库量
hist_outbound_mean 历史平均日出库量(可选择性排除出库为0的日期)
hist_outbound_std 日出库量的标准差
hist_outbound_median 日出库量的中位数
hist_outbound_MAD 基于中位数的绝对偏差(MAD)
hist_store_cnt_median 历史出库门店数的中位数
hist_store_cnt_MAD 门店数的MAD
这些统计值将作为自动设定“强铺货”判定阈值以及“常规销售”基准的重要依据。
(warehouse_id, sku_id)序列,
首销日期 first_sell_date = 最早 outbound_qty > 0 的 date
上新期长度 T_new = 按品类设定,常见 7–14 天(生鲜可以短一点)
在
[first_sell_date, first_sell_date + T_new - 1]这一时间段内,视为潜在的“上新观察期”。
outbound_store_cnt(t) > hist_store_cnt_median + K1 * hist_store_cnt_MAD
其中K1取值范围为2~3,可根据具体品类灵活调整。
- 出库总量明显偏高
outbound_qty(t) > hist_outbound_median + K2 * hist_outbound_MAD
也可使用分位数方式进行判断:
outbound_qty(t) > hist_outbound_Q90 (历史 90% 分位)
- 入库量异常增长(如有数据或通过推算获得)
inbound_qty(t) > hist_inbound_median + K3 * hist_inbound_MAD
综合判定规则示例:
若 t 在 [first_sell_date, first_sell_date + T_new - 1] 内,
且 (门店数显著高 OR 出库量显著高 OR 入库量显著高),
则状态 = "上新强铺货"。
可进一步细化为:
仅在上新初期的前3–5天出现集中放量,之后趋于平稳,则仅将最初几天标记为“上新强铺货”,后续转为“正常上架”状态。
outbound_qty = 0 ——即连续多日无出库;
同时
inventory_qty > 0 ——表示库存尚存但未释放;
并且该区间的前后均存在一定时期的出库行为,说明仅为阶段性中断。
K_min,例如2~3天;
- 最大允许天数
K_max,例如不超过10天(超过则更倾向归类为“长期下架”)。
对每个
(warehouse_id, sku_id)序列,
查找所有满足以下条件的日区间
[t_start, t_end]:
对于 t ∈ [t_start, t_end]:
outbound_qty(t) = 0
AND inventory_qty(t) > 0
区间长度 L = t_end - t_start + 1
K_min ≤ L ≤ K_max在区间前后存在出库的情形下,需对相关日期进行识别与标记处理。
在 [t_start - P, t_start - 1] 这 P 天中,存在 t',使 outbound_qty(t') > 0
并且 在 [t_end + 1, t_end + Q] 这 Q 天中,存在 t'',使 outbound_qty(t'') > 0
对于参数 P 和 Q 的取值,可设定为 7 天,或根据商品品类灵活配置。
针对满足条件的每一个日期 t ∈ [t_start, t_end],执行如下打标操作:
状态 = "短暂下架"
业务理解:
该 SKU 已基本从当前仓库的货架体系或运营流程中撤出,表现为长时间无法购买、不再补货。典型特征包括:
outbound_qty = 0
由于不同品类的商品生命周期差异显著,建议依据品类分别配置“长期下架”的判定天数阈值。
M
示例:
| 一级品类 | 短暂下架上限 K_max | 长期下架阈值 M |
|---|---|---|
| 生鲜 | 3–5 天 | 7–14 天 |
| 食品杂货 | 7–10 天 | 30 天 |
| 日化百货 | 10–14 天 | 30–60 天 |
对每个
(warehouse_id, sku_id)
,寻找满足以下条件的时间点:
存在连续 M 天区间 [t_start, t_end],对所有 t ∈ [t_start, t_end]:
outbound_qty(t) = 0
并且 (以下任一成立)
1)库存长期为 0 型:
inventory_qty(t) = 0 对所有 t ∈ [t_start, t_end]
2)库存极低且无入库型:
inventory_qty(t) ≤ I_low (小阈值,如 1 或 2)
且 inbound_qty(t) ≈ 0 (可以用 roll_30d_inbound_qty 很小来判断)
3)长期无流动型:
inbound_qty(t) ≈ 0 且库存几乎不变化(|inventory_qty(t) - inventory_qty(t-1)| ≤ δ)
同时确保在
[t_start - H, t_start - 1]
这一时间段内,商品曾有过稳定销量:
roll_30d_outbound_qty(t_start - 1) > V_min
若不满足上述销量条件,则可能属于从未真正上架推广的滞销品,不应标记为“下架”,而应归类为“未推广”状态。
对符合条件的每个日期 t ∈ [t_start, t_end],进行如下标记:
状态 = "长期下架"
业务理解:
该 SKU 在市场上具备需求基础(历史数据显示为动销商品),但当前仓库库存为 0 或远低于合理水平,且无出库行为,表明供应能力未能匹配市场需求。
缺货通常被视为最高优先级的运营问题。
inventory_qty(t) <= 安全库存阈值 I_safe(通常 0 或很小)
outbound_qty(t) = 0
或
outbound_qty(t) << hist_outbound_mean (比如 < 0.2 * hist_outbound_mean)
roll_30d_outbound_qty(t-1) > V_min
roll_30d_outbound_store_cnt(t-1) > S_min
store_order_qty(t) > 0 但 outbound_qty(t) = 0
对
(warehouse_id, sku_id, date=t)
,当满足:
if inventory_qty(t) <= I_safe
AND ( outbound_qty(t) = 0
OR outbound_qty(t) < α * hist_outbound_mean )
AND ( roll_30d_outbound_qty(t-1) > V_min
OR roll_30d_outbound_store_cnt(t-1) > S_min ):
状态 = "缺货"
其中:
I_safe 可设为 0,也可根据品类设定相应的安全库存基准;α 建议取值范围为 0.1~0.3;V_min 与 S_min 可通过全局统计或按品类确定。同一 SKU 在同一天可能符合多个状态判定规则(例如:库存为 0、长期无销量,同时刚过新品推广期)。因此,必须建立统一的状态优先级体系,以确保每日仅输出一个最终标签。
推荐优先级顺序(由高到低):
实现逻辑上,可采用逐层覆盖方式:
for 每个 warehouse_id, sku_id, date=t:
if 满足缺货条件:
label(t) = "缺货"
else if 满足上新强铺货条件:
label(t) = "上新强铺货"
else if 满足短暂下架条件:
label(t) = "短暂下架"
else if 满足长期下架条件:
label(t) = "长期下架"
else:
label(t) = "正常"
注意:
“长期下架”与“短暂下架”本质上是区间型属性,可先整体识别连续区间,再回填至每日记录。但在最终每日状态判定时,仍需按照上述优先级进行覆盖处理。
无需更改核心规则逻辑,只需保证所有计算均在
(warehouse_id, sku_id)
分组基础上独立运行即可。
伪代码示意:
按 (warehouse_id, sku_id) 分组:
按 date 排序
计算 rolling 指标 + 历史统计指标
计算首销日期 first_sell_date
扫描日期序列进行状态判断打标
多级品类主要用于差异化配置各类阈值参数,例如:
T_newK_min, K_maxMI_safeV_min, S_minK1, K2, K3建议构建一张“品类参数配置表”,示例如下:
| cate_1 | cate_2 | cate_3 | T_new | K_min | K_max | M | I_safe | V_min | S_min | α(缺货倍率) |
|---|---|---|---|---|---|---|---|---|---|---|
| 生鲜 | 水果 | 进口水果 | 5 | 2 | 5 | 10 | 5 | 3 | 0.2 | |
| 生鲜 | 肉禽蛋 | 冷鲜肉 | 3 | 2 | 5 | 7 | 5 | 3 | 0.2 | |
| 食品 | 饮料 | 碳酸饮料 | 10 | 3 | 10 | 30 | 2 | 10 | 5 | 0.3 |
| 日化 | 清洁 | 洗衣液 | 14 | 5 | 14 | 60 | 2 | 8 | 4 | 0.3 |
实际计算过程中,依据 SKU 所属的 cate_1/cate_2/cate_3 层级匹配对应参数。
提供一套可直接转化为 SQL 或 Python 代码的完整执行框架(按步骤说明)。
从原始业务系统中提取或汇总生成“日级库存+出库”明细表:
fact_daily_sku_warehouse
(
date,
warehouse_id,
sku_id,
cate_1, cate_2, cate_3,
inventory_qty,
outbound_qty,
outbound_store_cnt
)
若有入库数据,可通过 join 补充
inbound_qty
;若无,则可根据库存变动趋势反向推算入库情况。
对
(warehouse_id, sku_id)
进行分组,并按
date
排序,依次计算以下字段:
prev_inventory_qty —— 上一日库存inbound_qty —— 根据指定公式推导得出roll_7d_outbound_qty / roll_30d_outbound_qtyroll_7d_outbound_store_cnt / roll_30d_outbound_store_cntroll_7d_inbound_qty / roll_30d_inbound_qty同时计算必要的历史统计量:
hist_*
(可预先生成一张按 sku+仓 聚合的基础统计结果表)
对每个
(warehouse_id, sku_id)
:
first_sell_date步骤 3:识别下架区间
查找连续出现的
outbound_qty = 0
区间;对每一个这样的区间,依据其长度 L 判断属于“短暂下架候选”还是“长期下架候选”。
短暂下架候选:
- 区间内库存需大于 0;
- 区间前 P 天与后 Q 天均存在出库记录;
若满足上述条件,则将该区间内的每一天 t 标记为
label_candidate(t, "短暂下架") = 1
长期下架候选:
- 区间长度 L ≥ M(取自品类参数表);
- 区间内库存为 0 或处于极低水平,且无任何入库行为;
- 在区间开始之前存在历史销售行为;
若满足以上条件,则将该区间内所有时间点 t 标记为
label_candidate(t, "长期下架") = 1
实现方式上,可利用窗口函数对“连续零销量”段进行分组处理。例如采用“连续区间 ID”的技术方案——通过累计求和的方式划分不同的连续区间。
步骤 4:每日缺货判断
针对每个
(warehouse_id, sku_id, date=t)
执行以下操作:
I_safe
α
V_min
S_min
label_candidate(t, "缺货") = 1
步骤 2:确定最早铺货日期
通过查询品类参数表获取基础配置信息,并计算首个 outbound_qty > 0 的 date,即为该商品最早的实际发货日期。
T_new
在
[first_sell_date, first_sell_date + T_new - 1]
范围内,逐日判断是否达到“强铺货”标准(即是否超过设定阈值):
若满足条件,则标记为
label_candidate(t, "上新强铺货") = 1
步骤 5:基于优先级整合最终状态
对于每一个
(warehouse_id, sku_id, date=t)
综合已有候选标签并按照预设优先级规则进行决策输出:
if label_candidate(t, "缺货") == 1:
label_final(t) = "缺货"
elif label_candidate(t, "上新强铺货") == 1:
label_final(t) = "上新强铺货"
elif label_candidate(t, "短暂下架") == 1:
label_final(t) = "短暂下架"
elif label_candidate(t, "长期下架") == 1:
label_final(t) = "长期下架"
else:
label_final(t) = "正常"
最终生成一张完整的每日状态标识表,结果示意如下:
sku_warehouse_daily_status
(
date,
warehouse_id,
sku_id,
cate_1, cate_2, cate_3,
status -- {上新强铺货, 短暂下架, 长期下架, 缺货, 正常}
)
8.1 从未销售过的 SKU
若某个
(仓, SKU)
在其整个历史周期中
outbound_qty 始终为 0
:
建议在主流程启动前先行识别此类 SKU,避免被误判为“长期下架”或“短暂下架”情形。
8.2 清仓尾货场景识别
在某些长期下架发生前,可能出现短期内销量骤增随后迅速归零且不再补货的现象,属于典型的清仓行为。
若需单独区分,可引入附加规则(可选):
outbound_qty(t)
短时间内显著高于其历史平均水平;
inventory_qty=0
且
outbound_qty=0
满足上述模式的区间,可在后续标记为“清仓后下架”。尽管本质上仍属长期下架范畴,但可通过扩展标签增强业务解释性。
8.3 数据缺失与异常峰值处理
MAD
或基于分位数的方法进行 winsorize(截断处理);
未知
当前框架基于
纯规则+统计阈值构建,具备以下优势:
当数据量庞大、特征维度丰富时,可进一步演进为机器学习方案:
扫码加好友,拉您进群



收藏
