2. 间歇需求数据特征
间歇需求数据与连续需求数据在统计分布上存在本质差异。理解这些特征是构建因果特征与集成模型的前提。本章从四个核心维度展开:零膨胀、需求稀疏性、需求波动模式以及间歇性分类。
2.1 零膨胀(Zero-Inflation)
零膨胀是指数据中零值出现的频率远高于标准计数分布(如泊松分布)的预期。在供应链场景中,零值可能来自两种机制:
- 结构零(Structural Zero):该时间段内该SKU根本无需求(如季节性停产、产品退市)。
- 抽样零(Sampling Zero):理论上存在需求,但恰好在观测周期内未发生(如随机缺货、客户延迟下单)。
区分这两种零值对因果建模至关重要。若将结构零误判为抽样零,模型会错误地学习到“低需求”的因果路径,导致预测偏差。
关键指标: 零比例(Zero Ratio)= 零值周期数 / 总周期数。当零比例 > 0.5 时,需优先考虑零膨胀模型(如ZIP、ZINB)。
2.2 需求稀疏性(Demand Sparsity)
稀疏性描述的是非零需求事件之间的间隔长度。即使零比例相同,稀疏程度也可能差异巨大。例如,一个SKU每10周出现1次需求(间隔9周),与另一个SKU每10周出现2次但集中在同一周,其稀疏模式完全不同。
| 稀疏等级 | 平均需求间隔(ADI) | 典型场景 |
|---|---|---|
| 低稀疏 | ADI < 1.32 | 快消品、标准备件 |
| 中稀疏 | 1.32 ≤ ADI < 2.5 | 工业耗材、季节性配件 |
| 高稀疏 | ADI ≥ 2.5 | 航空备件、大型设备维修件 |
稀疏性直接影响模型的时间步长选择与特征窗口设计。高稀疏数据中,滑动窗口均值会引入大量零值噪声,需改用“事件间隔”作为因果特征的时间轴。
2.3 需求波动模式(Demand Volatility Pattern)
间歇需求不仅“稀疏”,而且“波动剧烈”。波动模式通常用需求变异系数(CV²)和需求峰度(Kurtosis)来刻画。
- CV²(变异系数平方):衡量非零需求量的离散程度。CV² > 1 表示高度波动,常见于促销驱动或项目型需求。
- 峰度:衡量极端大值的出现频率。高峰度(> 3)意味着存在“突发大单”,这类事件往往由外部因果事件(如政策变化、竞品断供)触发。
工程建议: 在特征工程中,将 CV² 和峰度作为分组特征,用于后续模型集成时的基学习器分配。高波动组优先使用树模型,低波动组优先使用线性模型。
2.4 间歇性分类(Intermittent Classification)
为了统一建模策略,业界通常将间歇需求数据分为四类。以下分类基于 Syntetos-Boylan 近似分类法,结合 ADI 与 CV² 两个维度:
基于上述分类,可制定差异化的特征工程与模型选择策略:
| 分类 | 因果特征重点 | 推荐基学习器 |
|---|---|---|
| 平稳间歇 | 历史均值、季节性虚拟变量 | Croston / 轻量GBDT |
| 波动间歇 | 促销日历、价格弹性、竞品事件 | XGBoost / LightGBM |
| 稀疏平稳 | 事件间隔、累计需求、外部宏观指标 | TSB / 贝叶斯结构时间序列 |
| 稀疏波动 | 因果图结构、干预变量、滞后效应 | 因果森林 / 深度状态空间模型 |
常见陷阱: 不要对所有间歇需求SKU使用同一套特征模板。例如,将“促销标志”作为特征加入稀疏平稳类,会导致过拟合,因为该类SKU几乎不参与促销。分类先行,特征后建。
2.5 特征工程中的零膨胀处理
在因果特征建模中,零膨胀数据需要特殊的特征变换:
- 零值标记特征:构造二元变量
is_zero,作为因果图中的干预节点。 - 间隔编码:将时间轴转换为“自上次非零需求以来的周期数”,作为连续特征。
- 累积需求窗口:使用“过去N次非零事件的总和”代替“过去N天的总和”,避免零值稀释信号。
# 示例:构造间隔编码与累积需求特征(Python伪代码)
import pandas as pd
def build_intermittent_features(df, sku_col='sku', date_col='date', demand_col='demand'):
df = df.sort_values([sku_col, date_col])
# 间隔编码
df['last_nonzero'] = df.groupby(sku_col)[demand_col].transform(
lambda x: x.eq(0).cumsum() - x.eq(0).cumsum().where(x.ne(0)).ffill().fillna(0)
)
# 累积需求(基于非零事件)
df['cum_demand_nonzero'] = df.groupby(sku_col)[demand_col].transform(
lambda x: x[x > 0].cumsum().reindex(x.index, method='ffill').fillna(0)
)
return df
通过上述特征变换,零膨胀数据中的“零”不再是噪声,而是携带因果信息的信号——它可能意味着库存充足、需求转移或外部事件缺失。