老王在城中村开了一家水果店,每天最头疼的事不是进货,而是“该进多少货”。进少了,顾客想买买不到,老王白白错过生意;进多了,水果隔夜就蔫,只能含泪扔掉。更让老王抓狂的是,他每隔几天就要搞一次促销——“苹果买一送一”“西瓜八折”。促销那几天,店里人山人海,销量蹭蹭往上涨;可促销一停,紧接着的两三天却门可罗雀,像被人按下了暂停键。老王原以为促销日的火爆就是水果店的“真实实力”,于是照着促销日的销量进货,结果促销一结束,仓库里的苹果堆成了山。 其实,老王踩中的正是零售需求预测里最经典的“促销效应”陷阱:促销日的销量,不全是“当下真实的需求”,而是三股力量的叠加——原本就会发生的自然购买、被折扣吸引来的新增需求,以及被提前透支的未来需求。只有把这三股力量拆开,算出“如果不促销,今天本来能卖多少”,才能做对进货决策。这个“不促销时的自然销量”,在行业里叫作基线销量;而“促销多卖出来的那部分”,叫作促销增量。测促销效应、拆增量、避透支、看溢出,就是本文要讲的全链路方法。

岗位关联

理解促销效应是 AI 零售需求预测的核心能力。掌握它,你就能从促销日的“假繁荣”中分辨真实信号,为企业做出更准的补货与定价决策——这正是供应链算法工程师和数据分析师最值钱的本事之一。

目录
  1. 可视化演示
  2. 促销困局:被“假繁荣”带偏的进货量
  3. 促销编码:给模型一张“促销日历”
  4. 基线估计:算出“不促销也能卖多少”
  5. 效应分解:把一桶水拆成两股源头
  6. 增量评估:这笔促销到底赚不赚
  7. 滞后效应:促销过后的“贤者时间”
  8. 交叉溢出:苹果打折,香蕉跟着沾光
  9. 落地实战:从账本到自动补货
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

促销困局:被“假繁荣”带偏的进货量

老王的水果店平时每天能卖 30 斤苹果。上周六他搞了“买一送一”,一天卖出 90 斤,老王高兴得合不拢嘴。第二天他果断进了一百斤苹果,结果只卖了 25 斤。老王盯着剩下的苹果发呆:是顾客不爱吃苹果了吗?当然不是——只是昨天该买的、不该买的、打算下周买的,都在打折那天提前买完了。

这 90 斤里,藏着三层秘密:第一层是“本来就会有的 30 斤”,这是老顾客雷打不动的日常消费;第二层是“被打折吸引来的新增需求”,比如本来打算买梨的人看见苹果便宜就改了主意;第三层是“从未来借来的需求”,有人把下周要吃的量提前囤进了冰箱。可以说,促销日的销量就像一杯加了三份浓缩的咖啡——它确实提神,但你不能把它当成日常的饮水量。

把这个场景放进数据里,问题就变得尖锐了:如果预测模型把促销日的 90 斤当成“正常需求水平”,它会立刻高估明天的需求。促销一结束,预测值和实际值就会大幅偏离。在零售需求预测中,这种“促销日被冲高、促销后被透支”的模式是最常见、最棘手的干扰源,行业里称之为促销效应。处理不好它,再高级的深度模型也会被带偏——毕竟,数据里的“假繁荣”越多,模型看到的规律越失真。

所以破解促销效应的第一步,是承认一个事实:促销日的高销量不是“纯天然”的。要预测明天,得先把今天打折带来的水分挤干,让数据回归到“没有促销时的朴素模样”。对老王来说,这意味着他需要一个能告诉“如果不促销,明天大概能卖多少”的帮手。这正是接下来我们要做的事。

促销编码:给模型一张“促销日历”

老王想了个笨办法:他在账本上给每个促销日画一个红勾,平时留白。这样月底盘点时,他一眼就能看出来哪些天搞过活动。小雅(老王的程序员外甥女)看完账本后,也照着这个办法帮 AI 学会了分辨“今天有没有促销”——不过它不画红勾,而是把促销日记成 1,把普通日记成 0。

在机器学习中,这串 0 和 1 被称为促销指示变量。它是最基础、最常用的促销编码方式:把第 t 天是否有促销事件转化为一个数值特征,方便模型把它当做一个“开关”来学习。模型发现:开关从 0 变成 1 的那几天,销量平均会多出 β 个单位——这个 β 就是促销的“平均拉动幅度”。

Pt={1,第 t 天有促销0,其他情况\displaystyle P_t = \begin{cases} 1, & \text{第 } t \text{ 天有促销} \\ 0, & \text{其他情况} \end{cases}

1. 定义 $P_t$:$P$ 是促销(Promotion)的缩写,下标 $t$ 表示第几天。$P_t$ 的含义是“第 $t$ 天有没有促销”这个标记。

Pt="第 t 天是否促销"P_t = \text{"第 } t \text{ 天是否促销"}

2. 值为 1 的情形:当第 $t$ 天老王贴出了促销牌,$P_t$ 就等于 1,表示这一天有促销活动。

Pt=1(有促销)P_t = 1 \quad (\text{有促销})

3. 值为 0 的情形:其余不搞促销的日子,$P_t$ 保持 0,表示没有促销活动。

Pt=0(无促销)P_t = 0 \quad (\text{无促销})

4. 模型如何使用:模型把整串 0 和 1 作为输入特征,学习“开关从 0 拨到 1”时销量平均增加多少,这个增加量就是促销系数。

ΔY=β⋅Pt\Delta Y = \beta \cdot P_t

当然,0-1 编码只是第一步。现实中的促销有直降、满减、买一送一,甚至还有“全场五折”这种大杀器。0-1 编码把所有促销都看作同一力度,显然会丢失信息。更精细的做法是按促销类型编码(直降=1、满减=2、买赠=3),或直接用折扣深度(八折=0.8、五折=0.5)当连续变量。但无论怎么升级,“0 代表不促销、1 代表促销”的指示变量始终是地基——它是让模型认识促销的第一块认知拼图。

老王看着账本上的红勾恍然大悟:原来让 AI 理解促销,就像教一个孩子认日历——你得先把“特殊的日子”标出来,孩子才知道哪天和平时不一样。标得越细,孩子对“这个日子有多特别”的理解就越准确。

基线估计:算出“不促销也能卖多少”

老王盯着账本上的红勾想:如果把这些日子遮住,剩下的普通日子的销量大概就是我“不搞促销的正常水平”吧?他翻了翻,上个月有 20 天没促销,销量分别是 28、31、29、30……平均下来差不多 30 斤。这就是他心里的“日常销量”。

在需求预测里,这个“不促销时的自然销量”叫基线销量。它不是算命,而是可以从数据中估计的。最简单的估计方法,就是取非促销日的历史平均;更聪明一点的做法,是用指数平滑——让基线既吸收最近的变化,又不被促销日的尖峰带偏:

B^t=α⋅Xt−1+(1−α)⋅B^t−1\displaystyle \hat{B}_t = \alpha \cdot X_{t-1} + (1-\alpha) \cdot \hat{B}_{t-1}

1. 识别 $\hat{B}_t$:带着“小帽子”的 $B$ 表示估计值,即模型认为的第 $t$ 天“不促销也能卖出去”的自然销量。

B^t=今天的基线估计\hat{B}_t = \text{今天的基线估计}

2. 理解 $\alpha$:平滑系数,取值在 0 到 1 之间。它代表老王有多相信“昨天的实际销量”。

0≤α≤10 \le \alpha \le 1

3. 检查 $X_{t-1}$:昨天的真实销量。注意,如果昨天是促销日,这一项要先把促销增量剔掉,否则会把促销的“假高”带进基线。

Xt−1=真实销量−促销增量X_{t-1} = \text{真实销量} - \text{促销增量}

4. 保留历史记忆:$(1-\alpha) \cdot \hat{B}_{t-1}$ 是昨天的基线按权重保留下来,相当于模型的“长期记忆”。

记忆项=(1−α)⋅B^t−1\text{记忆项} = (1-\alpha) \cdot \hat{B}_{t-1}

5. 整体效果:今天的基线 = 新信息与老记忆的折中。这个平滑过程能像熨斗一样,把促销日凸起的尖峰熨平,还原出平滑的自然需求曲线。

B^t=α⋅Xt−1+(1−α)⋅B^t−1\hat{B}_t = \alpha \cdot X_{t-1} + (1-\alpha) \cdot \hat{B}_{t-1}

在实际建模中,基线还会加入星期因素和季节因素——比如周末需求天然比工作日高 20%,夏天水果整体走量快。这些因素写成回归项或乘性因子,都能让基线更贴近真实。但核心思想不变:基线必须“躲开”促销日,只看自然状态下销量应该有的样子。

老王把这个方法记在本子上:基线不是拍脑袋的平均数,而是一条会呼吸的曲线——跟着星期起伏,跟着季节爬坡。有它在手,老王终于有了一个衡量促销的“参照物”,接下来就能把促销日的销量拆开看个明白了。

效应分解:把一桶水拆成两股源头

促销日上午十点,老王店里的苹果已经卖掉大半。他看着不断跳动的销量数字,心里默念:这 90 斤里,哪些是“本来就会买的”,哪些是“促销拉来的”?回想一下:今天的基线大约是 30 斤,那多出来的 60 斤,自然就是促销的功劳了。

这个“总销量减基线”的朴素操作,正是促销效应分解的核心。把每一天的销量看作两块积木的叠加——底层是基线,上层是促销增量。写成公式就是:

Yt=B^t+β⋅Pt+εt\displaystyle Y_t = \hat{B}_t + \beta \cdot P_t + \varepsilon_t

1. 识别 $Y_t$:第 $t$ 天账本上记录的实际总销量,比如老王昨天看到的 90 斤苹果。

Yt=实际总销量Y_t = \text{实际总销量}

2. 识别基线 $\hat{B}_t$:基线销量,即便今天完全不促销、不搞活动,也依然会有人来买的自然销量。

B^t=基线销量\hat{B}_t = \text{基线销量}

3. 识别促销项 $\beta \cdot P_t$:促销增量项。$\beta$ 是促销系数,表示“促销一次平均多卖多少”;$P_t$ 是 0 或 1,所以促销日这整项生效,非促销日自动消失。

β⋅Pt={β,Pt=10,Pt=0\beta \cdot P_t = \begin{cases} \beta, & P_t = 1 \\ 0, & P_t = 0 \end{cases}

4. 识别噪声 $\varepsilon_t$:随机误差,比如忽然下暴雨、隔壁超市关门,这些没法建模的偶然因素都归到这里。

εt=随机波动\varepsilon_t = \text{随机波动}

在实际项目中,$\beta$ 不是拍脑袋定的,而是通过历史数据拟合出来的。把过去几个月的销量、促销标记一起喂给线性回归或树模型,模型会自己学到“促销平均拉动多少销量”。更高阶的做法是把多个促销变量(折扣深度、促销类型)同时放进模型,让分解更精细——本质仍是这同一个加法框架。

老王看着分解结果,第一次觉得账算明白了:90 斤苹果里,30 斤是老顾客的日常需求,60 斤才是促销真正吸引来的额外生意。他不需要再对着总销量发愁,因为每一块销量都有了来路。

增量评估:这笔促销到底赚不赚

能拆出 60 斤增量后,老王反而更纠结了:这 60 斤苹果确实多卖了,可“买一送一”意味着有一半是白送的,再加上印传单的钱,到底赚了没有?邻居老李给老王出了个主意:算算“多卖的部分值多少钱”和“少赚的让利多少钱”,一比就知道。

这正是促销增量评估的思路:先算增量销量,即所有促销日实际销量超过基线的部分之和:

增量销量=∑t∈促销期(Yt−B^t)\displaystyle \text{增量销量} = \sum_{t \in \text{促销期}} \left( Y_t - \hat{B}_t \right)

1. 认识求和符号:$\sum$ 表示求和,把一段时期内的数据逐日累加。

∑t=1nat=a1+a2+⋯+an\sum_{t=1}^{n} a_t = a_1 + a_2 + \cdots + a_n

2. 计算括号里的差值:第 $t$ 天的实际销量减去当天基线,得到“当天多卖的量”,也就是促销贡献。

Yt−B^t=当天增量Y_t - \hat{B}_t = \text{当天增量}

3. 限定累加范围:只累加那些搞了促销的日子,避免把普通日的正常波动也混进来。

t∈{促销日}t \in \{\text{促销日}\}

有了增量销量,还差最后一步:把它换成钱。假设每斤苹果净利润 3 元,这次促销多卖 60 斤,增量毛利就是 180 元;但让利、传单、人工总共花了 80 元。投入 80 元换回 180 元毛利,值不值?用促销 ROI 来衡量:

ROI=增量毛利−促销成本促销成本\displaystyle \text{ROI} = \frac{\text{增量毛利} - \text{促销成本}}{\text{促销成本}}

1. 计算增量毛利:只计算“比不促销多卖出去”的那部分产品带来的毛利,这是分子里最关键、也最容易被错用的数。

增量毛利=增量销量×单位毛利\text{增量毛利} = \text{增量销量} \times \text{单位毛利}

2. 核算促销成本:让利损失、物料、广告等所有花在本次促销上的钱,都要折算进来。

促销成本=让利+物料+人力\text{促销成本} = \text{让利} + \text{物料} + \text{人力}

3. 做差再相除:先用增量毛利减去促销成本得到净收益,再除以成本就得到每一块钱投入的回报率。ROI 大于 0 才值得做。

ROI=增量毛利−促销成本促销成本\text{ROI} = \frac{\text{增量毛利} - \text{促销成本}}{\text{促销成本}}

老王算了半天,发现“苹果买一送一”的 ROI 只有 0.6——表面热闹,实际不如不做。他感慨道:促销不是看卖得爽不爽,而是看“比不促销多赚了多少”,以及“多赚的钱够不够填上让利的坑”。这才是增量评估的灵魂。

滞后效应:促销过后的“贤者时间”

老王又发现一个规律:每次促销结束后的两三天,店里都格外冷清。不是顾客不来了,而是打折时大家都囤够了。老王管这叫“吃完大餐后的贤者时间”——肚子饱了,后面几顿自然吃不下。

这个现象在行业里叫滞后效应。促销不仅影响当天,还会影响未来几天:促销当日拉高销量,随后的几天把“未来的需求”提前消耗掉,销量低于基线。如果模型只看当天,就会高估促销的净收益——因为它漏掉了促销欠下的“未来账”。

把滞后效应写进模型,只需在方程里多放几个昨天的、前天的促销变量:

Yt=B^t+β0Pt+β1Pt−1+β2Pt−2+εt\displaystyle Y_t = \hat{B}_t + \beta_0 P_t + \beta_1 P_{t-1} + \beta_2 P_{t-2} + \varepsilon_t

1. 即时拉动 $\beta_0 P_t$:今天的促销对今天销量的即时影响,通常是一个较大的正数。

β0Pt(今天促销才生效)\beta_0 P_t \quad (\text{今天促销才生效})

2. 滞后项 $\beta_1 P_{t-1}$:昨天如果搞了促销,对今天销量的影响。因为顾客昨天刚囤过货,这个系数往往为负。

β1Pt−1(昨天促销才生效)\beta_1 P_{t-1} \quad (\text{昨天促销才生效})

3. 滞后项 $\beta_2 P_{t-2}$:前天促销对今天的影响,幅度通常更小,且在三天后会逐渐消失。

β2Pt−2(前天促销才生效)\beta_2 P_{t-2} \quad (\text{前天促销才生效})

4. 噪声项 $\varepsilon_t$:吸收无法解释的偶然波动。

εt=随机项\varepsilon_t = \text{随机项}

5. 净效果计算:把三个促销系数全部相加,才是促销在整个时间窗上的净增量,单独看任何一天都会误判。

净效果=β0+β1+β2\text{净效果} = \beta_0 + \beta_1 + \beta_2

在实际系统里,滞后窗口会扩展到 7 到 14 天,参数也可以通过分布滞后(如指数衰减权重)来压缩。理解了滞后效应,老王就能回答那个经典问题:“促销是不是寅吃卯粮?”答案是:如果透支远超新增,那确实是——而模型的作用,就是把“卯粮”也算清楚。

交叉溢出:苹果打折,香蕉跟着沾光

一段时间后,老王发现了个有趣现象:每次苹果搞促销,隔壁香蕉的销量也会往上蹿一截。一开始他以为是巧合,后来发现每次促销都这样。原来顾客本来是来买打折苹果的,看到香蕉又新鲜又黄亮,顺手就带了一串回家。

一个品类的促销影响另一个品类的销量,这叫跨品类溢出效应。当两个品类是互补关系时(苹果和香蕉常一起吃),促销会带来正溢出;如果是替代关系(红富士和嘎啦果),促销则会抢走对方的生意,造成负溢出。忽略溢出效应,会低估促销的涟漪范围。

QB,t=B^B,t+γ⋅PA,t+εt\displaystyle Q_{B,t} = \hat{B}_{B,t} + \gamma \cdot P_{A,t} + \varepsilon_t

1. 识别 $Q_{B,t}$:品类 B 在第 $t$ 天的实际销量,比如香蕉的当日销量。

QB,t=香蕉当日销量Q_{B,t} = \text{香蕉当日销量}

2. 识别 $\hat{B}_{B,t}$:品类 B 自己的基线销量,即在没有任何促销干扰时,香蕉自然能卖出的数量。

B^B,t=香蕉的自然销量\hat{B}_{B,t} = \text{香蕉的自然销量}

3. 理解溢出项 $\gamma \cdot P_{A,t}$:品类 A 的促销对 B 的溢出项。$\gamma > 0$ 说明 A 促销带旺了 B(互补),$\gamma < 0$ 说明 A 促销挤掉了 B 的生意(替代)。

γ⋅PA,t(γ>0 互补,γ<0 替代)\gamma \cdot P_{A,t} \quad (\gamma>0 \text{ 互补,} \gamma<0 \text{ 替代})

4. 噪声项:随机波动,吸收意料之外的因素。

εt=随机项\varepsilon_t = \text{随机项}

在真实系统中,溢出矩阵可以覆盖几十个品类:比如“薯片和啤酒”互相带动,“可乐和雪碧”互相争夺。建模时一般把品类两两的溢出系数放进一起训练,或用图神经网络捕获高阶传播。老王受此启发,把“红富士打折、嘎啦少进货”写进了自己的采购口诀——促销不是一个摊子的事,而是一张全村的地图。

落地实战:从账本到自动补货

老王折腾了大半年,总算把这套方法理顺了。小雅帮他把所有经验写进了一个自动补货小程序:每天凌晨,程序自动读取昨天的销量、今天的促销计划、天气预报和节假日安排;先剔除促销日的干扰估计当天基线,再叠加上促销增量、扣掉滞后透支、算上跨品类溢出,最后给出一个备货建议。

这条链路正是零售业促销效应预测落地的标准流程:数据清洗与促销标注 → 基线估计 → 增量建模(含滞后、溢出)→ 预测集成与部署 → 促销复盘校准。每一步都有坑:促销标注不完整,模型会漏掉效应;基线不及时更新,促销后就会高估需求;只部署不监控,遇到“全场五折”这种极端促销,误差会瞬间爆表。

落地的实操建议有三条:第一,把促销日历提前录入系统,让模型在预测前就知道哪天有活动;第二,用“预测-实际”差值做一个监控看板,促销日和非促销日分开盯;第三,每次大促之后做一次归因复盘,用最新数据重新校准促销系数——促销的“脾气”会随季节、市场竞争不断变化。

老王的水果店从此告别了“拍脑袋进货”。促销在他眼里不再是洪水猛兽,而是一套可预测、可衡量的规律:基线是底、增量是浪、透支是余波、溢出是涟漪。只要看懂了这些,每一次打折潮都能被稳稳接住。

AI 应用场景

大促前的备货决策

阶段:需求预测与库存计划

解决的问题:传统备货靠“历史同期销量乘以 1.5”的拍脑袋公式,把促销增量与基线混为一谈,导致大促后库存积压、非促销日缺货。AI 通过基线-增量分解,让每个 SKU 拿到差异化的备货建议。

具体案例:某连锁超市在"618"前对 2000 个 SKU 先估计无促销基线,再叠加大促增量系数、剔除促销后两周的透支影响,自动生成备货量。结果大促期缺货率下降 18%,促销后两周的滞销库存减少 32%。

促销日历与跨品类联动

阶段:营销策略优化与促销归因

解决的问题:传统按品类独立规划促销,看不到互补品和替代品之间的此消彼长。AI 用溢出系数矩阵发现品类间的“串门效应”,从而优化促销日历和商品摆放。

具体案例:一家生鲜电商发现“三文鱼促销”对“柠檬”有强正向溢出(溢出系数 > 0.3),于是把柠檬作为“凑单推荐”放在三文鱼促销页,同时避免与虾(替代品)同期打折。每万元促销预算带来的增量营收提升了约 22%。

Python 演示

python49 行
import numpy as np  def simulate_sales(n=60, promo_days=(15, 16, 17, 40, 41), seed=7):    # 模拟一家水果店的日销量.    # 销量 = 基线(季节波动) + 促销增量 + 促销后透支 + 随机噪声.    rng = np.random.default_rng(seed)    t = np.arange(n)    baseline = 20 + 3 * np.sin(2 * np.pi * t / 12)    is_promo = np.zeros(n, dtype=bool)    for d in promo_days:        is_promo[d] = True    lift = np.where(is_promo, 10.0, 0.0)    drag = np.zeros(n)    for d in promo_days:        if d + 1 < n:            drag[d + 1] -= 4.0        if d + 2 < n:            drag[d + 2] -= 2.0    noise = rng.normal(0, 1.2, n)    return baseline + lift + drag + noise, baseline, is_promo  def estimate_promo_effect(sales, is_promo):    # 用对比法分解促销效应.    # 非促销日的平均销量当作基线, 促销日超出基线的部分就是平均增量.    normal = sales[~is_promo]    baseline = normal.mean()    promo = sales[is_promo]    avg_lift = promo.mean() - baseline    total_lift = (promo - baseline).sum()    return baseline, avg_lift, total_lift  def main():    sales, baseline, is_promo = simulate_sales()    b, lift, total = estimate_promo_effect(sales, is_promo)    promo_days = np.where(is_promo)[0]    after_days = np.minimum(promo_days + 1, sales.size - 1)    after_avg = sales[after_days].mean()    print("基线销量(非促销日均值): %.1f 份" % b)    print("促销平均增量: +%.1f 份" % lift)    print("促销期总增量: +%.1f 份" % total)    print("促销次日平均销量: %.1f 份 (比基线低 %.1f)" % (after_avg, b - after_avg))    print("结论: 促销当日有增量, 但次日销量低于基线, 说明存在需求透支.")  if __name__ == "__main__":    main()
目的:模拟一家水果店带促销、透支和噪声的日销量数据,并用“非促销日均值 vs 促销日均值”的对比法,把促销增量从总销量中分解出来,顺便发现次日需求被透支的证据。
  1. baseline = 20 + 3 * np.sin(2 * np.pi * t / 12)生成一条有季节波动的自然销量曲线,作为“如果不促销会怎样”的答案。
  2. lift = np.where(is_promo, 10.0, 0.0)促销日模拟多卖 10 份,这就是人为埋入的“促销增量”。
  3. drag[d + 1] -= 4.0促销后第一天销量被透支 4 份,模拟顾客提前囤货。
  4. normal = sales[~is_promo]用布尔索引取出所有非促销日的销量,作为估计基线的素材。
  5. avg_lift = promo.mean() - baseline促销日均值减去基线,得到“促销平均带来多少增量”。
  6. after_days = np.minimum(promo_days + 1, sales.size - 1)取每个促销日的次日,并防止越界。
  7. print("促销次日平均销量: ...")输出次日均值,若明显低于基线,就验证了滞后透支。

常见误区

误区促销日销量暴增,说明顾客购买力强,这才是市场的真实需求。平时卖得少反而是“不正常”的,应该按促销日的量来备货。

正解促销日的销量里既包含被折扣激发的新增需求,也包含被提前透支的未来需求。真正的“真实需求”应该看基线。如果按促销日的量备货,促销一结束就会严重积压。就像老王促销后进了一百斤苹果只卖出 25 斤,不是顾客消失了,而是需求被提前花完了。

为何常见:促销日的数据太显眼,人天生容易被“看得见的高销量”吸引;而“如果不促销会怎样”是一个反事实问题,需要专门建模才能回答。

误区有促销就记 1,没促销就记 0,模型学到的增量系数就是促销的平均效果。何必把折扣力度、促销类型搞得那么复杂?

正解八折和五折带来的增量天差地别,0-1 编码把“力度”这层信息抹平了。实际工作中常用折扣深度(0.8、0.5)或促销类型编码(直降、满减、买赠),否则模型会系统性低估大促、高估小促。

为何常见:0-1 编码是入门教程最常出现的形式,写法最简单,容易让人误以为这是终点而非起点。

误区基线基线,就是历史销量的平均值呗,算一次可以用一年,不用天天更新。

正解基线会随着星期、季节、趋势变化而起伏——苹果夏天卖得少、周末卖得多,还有缓慢的长期爬坡。基线应该是一条动态曲线,用指数平滑或季节分解定期更新,才能跟上市场的变化节奏。

为何常见:“平均”这个概念太深入人心,用平均当基线最直观,但平均恰恰会把季节波动和趋势信息全部抹平。

误区搞促销嘛,效果就是当天多卖一点,算完当天的增量就结束了,不用看后面几天。

正解促销还有“滞后透支”和“跨品类溢出”两种隐藏效果。促销结束后的两三天销量往往明显低于基线,这是消费者提前囤货;同时互补品类可能被带动、替代品类可能被挤压。只看当天,会把透支当增长,也会漏掉溢出带来的收益。

为何常见:单日销量的因果最直观,滞后和溢出需要拉长时间窗、横跨品类去看,初学者很难一步想到。

误区促销期间销量涨了 80%,这 80% 全是促销的功劳,增量评估直接用促销前后销量做差就行。

正解促销期间可能叠加节假日、周末、季节因素,“净增量”要把这些因素和基线一起剔掉。比如周末本来就会多卖 20%,促销在周末的净增量应该用“周末预期销量”作基线,而不是拿周一当参照。否则会把自然增长错误地记到促销头上。

为何常见:人天生倾向把结果归因于最显眼的事件(促销),而忽视背景因素(周末、季节),这是典型的归因偏差。

面试题

Q1. 做促销效应分解时,最核心的第一步是什么?

单选题 · easy

  • A.立即设计新的促销方案
  • B.准确估计无促销时的基线销量← 正确答案
  • C.把所有销量都归因于促销效果
  • D.删除所有促销日的数据

答案:B。促销效应分解的本质是“总销量 = 基线 + 促销增量”。如果没有一个可靠的基线,“增量”就无从谈起。把促销日销量全归给促销会高估效果,删数据又会丢失信息,所以第一步永远是估计基线。

Q2. 促销变量最基础的编码方式是什么?

单选题 · easy

  • A.用 0-1 指示变量标记促销日← 正确答案
  • B.用随机大数标记促销力度
  • C.只保留促销日的销量记录
  • D.把促销日直接标记为缺失值

答案:A。0-1 指示变量(1=有促销,0=无促销)是最简单也最常用的编码,让模型把促销当做一个“开关”来学习。随机大数、删数据、标缺失都会扭曲信息,属于错误做法。

Q3. 老王的水果店平时每天卖 20 斤苹果,促销那天卖了 50 斤。促销增量是多少?

单选题 · mid

  • A.50 个
  • B.20 个
  • C.30 个← 正确答案
  • D.70 个

答案:C。增量 = 实际销量 - 基线 = 50 - 20 = 30 斤。50 是总销量,20 是本来就有的自然需求,只有多出的 30 斤才是促销真正带来的贡献。

Q4. 促销结束后的第二天,销量明显低于基线,最可能的原因是什么?

单选题 · mid

  • A.顾客对老王的水果失去兴趣
  • B.需求被促销透支,顾客已提前囤货← 正确答案
  • C.销量预测模型计算出错
  • D.天气突然变冷导致购买减少

答案:B。这是典型的滞后效应/需求透支:促销时顾客把未来几天的量提前买走了,次日需求自然回落。这并非顾客流失,也未必是模型错误或天气原因,而是促销“寅吃卯粮”的体现。

Q5. 以下哪些做法有助于更准确估计基线销量?

多选题 · mid

  • A.参考去年同期非促销日的销量← 正确答案
  • B.剔除促销日数据再求平均← 正确答案
  • C.考虑季节趋势与星期因素← 正确答案
  • D.把促销日销量直接当作基线

答案:ABC。基线是“不促销时的自然销量”,所以要看非促销日、剔除促销日干扰,并考虑季节和星期波动。把促销日销量直接当基线,恰恰会把“假繁荣”当成常态,是最常见的错误。

Q6. 某产品促销后,隔壁货架 B 产品的销量也明显上涨。这种现象叫什么?

单选题 · hard

  • A.促销的滞后透支效应
  • B.跨品类交叉溢出效应← 正确答案
  • C.促销的需求透支效应
  • D.基线的自然漂移效应

答案:B。A 产品促销带动 B 产品销量,是典型的跨品类溢出效应。滞后透支是促销结束后自身销量回落,自然漂移与促销无关。互补品之间常出现正溢出,替代品之间则可能是负溢出。

Q7. 促销 ROI 的正确衡量方式是什么?

单选题 · mid

  • A.用促销总收入减去促销总成本
  • B.用增量毛利减去成本再除以成本← 正确答案
  • C.用促销日总销量作为收益指标
  • D.用平时销量增长率估算收益

答案:B。ROI = (增量毛利 - 促销成本) / 促销成本。关键在“增量”二字——只有比不促销多赚的钱才算收益。用总销售额或总销量会混入本来就会发生的自然购买,高估促销价值。

Q8. 设计一个促销效应预测模型时,应该纳入哪些因子?

多选题 · hard

  • A.当期促销指示变量与力度← 正确答案
  • B.过去两三天的促销滞后项← 正确答案
  • C.相邻互补品类的溢出影响← 正确答案
  • D.消费者的手机品牌与型号

答案:ABC。完整的促销效应模型应包含当期促销变量(力度/类型)、滞后项(捕捉透支)和交叉品类项(捕捉溢出)。手机型号与销量预测无关,属于无关特征,引入反而会增加噪声。

Q9. 为什么不能把促销日的销量直接当成真实需求?

单选题 · easy

  • A.促销日的销量数据本身是虚构的
  • B.促销销量混合了透支与新增需求← 正确答案
  • C.促销日根本没有顾客来买东西
  • D.促销日的销量统计口径不一致

答案:B。促销日销量 = 自然需求 + 促销新增 + 未来需求透支。它是一杯“浓缩咖啡”,不能代表日常水平。直接用会高估后续需求,导致促销后库存积压。

Q10. 促销效应模型从数据到落地部署,通常包括哪些环节?

多选题 · hard

  • A.数据清洗与促销活动的标注← 正确答案
  • B.基线估计与增量效应建模← 正确答案
  • C.模型部署与促销复盘监控← 正确答案
  • D.永久停掉所有促销活动

答案:ABC。标准链路是:清洗并标注促销日历 → 估计基线 → 建模增量(含滞后、溢出)→ 部署监控 → 复盘校准。停掉所有促销虽然能避免促销效应,但也放弃了增长机会,属于因噎废食,不是工程方案。