申请体验
控制变量 · 方法论深度解析

促销、价格与缺货:三个最容易被 MMM 错算成广告贡献的变量

大促期间广告加码、折扣加深、库存快速消耗,销售也同步上涨。模型看到的是相关性;如果没有把促销、成交价和可售状态正确放进方程,渠道 ROI 很可能从一开始就算错了。

SparkX 团队2026 年 9 月 29 日约 18 分钟阅读
目录
同涨不等于广告带来增长 遗漏变量偏差怎么产生 促销:一个 0/1 标签通常不够 价格:应该用标价还是成交价 缺货:观测销售不等于真实需求 先判断变量的因果角色 三类变量如何构造 交互项什么时候需要 怎么验证变量加对了 示例:ROI 如何被重新分配 五个常见错误 Q4 建模前检查清单

同涨不等于广告带来增长

假设一个品牌在大促周把 Meta 和 Google 预算提高 60%,同时把主力商品从原价 499 元降到 399 元。销量翻倍后,模型如果只看渠道花费和销售额,很自然会把大部分增长分给广告。问题是,消费者究竟因为看到了更多广告而购买,还是因为价格下降 20% 才购买?如果促销和媒体总是一起发生,历史数据本身很难把两者自动拆开。

缺货会制造相反方向的错误。广告把需求推高,但主力 SKU 在周中断货,最终记录的销售额被库存上限截断。模型看到“高花费但销售没有继续增长”,可能误判渠道已经饱和、ROI 很低。真实情况却是需求存在,只是没有库存可以完成交易。

核心问题

MMM 的目标变量通常是观测到的销售或收入,而业务真正关心的是需求与媒体增量。促销和价格会改变需求,缺货会限制需求转化为销售。三者如果被遗漏、口径错误或放错因果位置,都会把非媒体效应转移到渠道系数上。

遗漏变量偏差怎么产生

为了看清机制,先把真实的数据生成过程简化为:

Salest = βm Mediat + βp Promot + Controlst + εt

如果模型漏掉 Promo,而促销期间又恰好加大媒体投放,那么估计出来的媒体系数不只包含媒体自身效应,还会吸收与媒体相关的促销效应。在线性简化下:

Bias(β̂m) = βp · Cov(Media, Promo) / Var(Media)

当促销提高销售(βp > 0)且促销与广告同向变化时,媒体系数通常被向上推;如果折扣期广告反而收缩,偏差方向也可能相反。因此“遗漏促销一定高估广告”不是普适定律,偏差方向取决于变量对 KPI 的影响方向以及它与媒体的相关方向。

公式同样适用于价格、库存、门店覆盖、竞品活动和宏观需求。遗漏变量偏差的关键不是“模型少了一列”,而是被遗漏变量同时影响 KPI,并且与已纳入的媒体变量相关。

促销:一个 0/1 标签通常不够

促销日历是很好的起点,但单一 promo_flag 只能告诉模型“这一周有促销”,不能区分九折、七折、满减、优惠券、Prime Day 或全店大促。它默认所有促销强度和作用方式相同,这在 Q4 通常不成立。

字段示例回答的问题注意事项
促销标记promo_flag = 0/1有促销与无促销的平均差异数据少时稳定,但无法表达强度
折扣深度1 - net_price/list_price折扣每加深一个百分点的影响要用实际支付口径,不能只看页面标价
促销类型满减、券、会员价、大促不同机制是否有不同 lift类型太多会稀释样本,先合并业务相近活动
促销覆盖率促销 SKU 销售前权重活动覆盖了多少业务体量避免用活动后销售权重,后者已经受结果影响

还要区分促销的即时效应和跨期效应。囤货型品类在大促周销量上升,之后几周可能回落,这是消费者提前购买造成的 pull-forward,而不是需求永久增加。只放当周标签,模型可能把大促后的回落错误归因给广告衰减或渠道疲劳。可根据业务机制加入有限的促销前导/滞后项,但不应无约束地堆很多 lag。

价格:应该用标价还是成交价

价格变量最常见的错误是使用商品标价。真正影响消费者选择和企业收入的,通常是扣除券、满减、会员优惠后的实际成交价(net realized price)。多 SKU 业务还需要控制产品组合:高价 SKU 占比上升会推高平均成交价,即使每个 SKU 都没有涨价。

更稳健的做法是构造可比价格指数,例如固定一组 SKU 权重计算周度价格,或者在可行时先到 SKU/品类层建模再汇总。简单的收入加权平均价存在机械关系:收入本身参与了价格计算,畅销商品的销量变化会改变权重,可能引入内生性。

Laspeyres Price Indext = Σi pi,t qi,0 / Σi pi,0 qi,0

固定基期数量权重的价格指数能减少销售结果反过来改变权重的问题,但仍不能自动解决定价内生性。企业往往在预期需求疲软时降价,在预期旺季时涨价;此时价格由需求预期共同决定。MMM 中加入价格可以减少遗漏偏差,却不意味着价格系数天然具有严格因果解释。若目标是估计价格弹性,通常需要更强的识别设计、工具变量、自然实验或受控价格测试。

缺货:观测销售不等于真实需求

缺货时,数据记录的是“能卖出去多少”,不是“消费者想买多少”。可以把观测销售理解为受供给约束的结果:

Observed Salest = min(Latent Demandt, Available Supplyt)

一个简单 stockout_flag 也常常不够。周日断货和周一断货都标记为 1,但损失完全不同;一个边缘 SKU 缺货与主力 SKU 缺货也不应等权。更好的变量包括可售率、缺货天数占比、按历史销售权重计算的库存可用率,以及可售门店/配送区域覆盖率。

缺货变量的作用还取决于 KPI:

控制缺货仍不能恢复全部丢失需求

把可售率放进回归可以减少渠道系数偏差,但一个线性控制项通常无法精确推断缺货期间本来会卖多少。严重缺货期可以做敏感性分析、使用流量/加购等需求代理,或在有充分依据时将其视为截尾观测;不能简单把缺货周删除,因为缺货往往正是高需求和高投放共同造成的,删除会形成选择偏差。

先判断变量的因果角色

“与销售相关”不等于“应该控制”。在加入任何变量前,先画出业务因果路径,判断它发生在媒体之前、媒体之后,还是与媒体和销售共享上游原因。

角色典型路径建模原则
混杂变量大促计划 → 广告加码;大促计划 → 销售增长通常需要控制,否则促销效应会进入媒体系数
中介变量广告 → 网站流量/品牌搜索 → 销售估计广告总效应时不应作为普通控制变量直接截断;需要中介或 Full-Funnel 结构
碰撞变量广告 → 缺货 ← 自然需求机械控制可能打开虚假关联;应结合库存机制和目标 estimand 设计
结果代理销售增长 → 动态调价或追加促销可能内生,不能仅凭相关性解释为原因

例如网站会话数看起来是很好的需求控制,但如果大部分会话由广告产生,它就是媒体效应的一部分。把它塞进标准 MMM 会让模型只估计“控制流量后的广告直接效应”,系统性低估广告总效应。类似地,广告导致需求暴增后引发缺货,缺货既是供给约束,也可能位于广告影响销售的路径上;此时要先说明目标是估计实际已实现收入,还是无库存约束下的潜在需求。

三类变量如何构造

字段设计应优先使用在决策时可获得、口径稳定、不会机械使用目标变量的信息。下面是一套周度 DTC / 电商 MMM 的实用起点:

业务概念推荐字段不推荐的替代原因
促销折扣深度、活动类型、覆盖率、活动前后有限 lag所有活动共用一个永久不变的 dummy强度和机制不同
价格实际成交价指数、固定 SKU 权重、相对竞品价简单收入/销量得到的平均售价与 KPI 机械相关,且受产品组合影响
库存可售率、缺货天数占比、主力 SKU 加权可用率周内任何缺货即记 1不能表达持续时间和业务权重
分销可售门店数、可配送邮编覆盖、有效 listing 数累计注册门店或历史 listing不代表当周真实可购买范围

所有连续变量都应检查异常值、定义变化和缺失机制。缺失库存数据不能默认填 0,因为 0 通常意味着“完全无库存”,而不是“未知”;价格缺失也不应直接前向填充跨过换品或币种变化。字段口径发生变化时,应增加定义变更标记或重新构造一致历史。

交互项什么时候需要

媒体和促销可能不只是相加。大促落地页、优惠价格和广告曝光共同出现时,广告转化效率可能显著提高,可以用有限且有业务依据的交互项表达:

Salest = ... + βm Mediat + βp Promot + βmp(Mediat × Promot) + εt

但交互系数要求数据里同时存在“有/无促销”和不同媒体强度的足够变化。如果品牌每次促销都把广告固定提升到同一个水平,主效应和交互效应仍然不可识别。不要为每个渠道、每种促销都创建交互项;参数数量会迅速超过周度样本能够支持的范围。可以先用业务假设选择一两个关键交互,再通过时间回测和正则化检验是否带来稳定增益。

怎么验证变量加对了

加入业务控制变量后,不要只看训练集 R² 是否提高。一个变量可能仅仅更会解释历史,甚至把媒体真实效应截走。建议按以下顺序验证:

  1. 先检查时间和口径:促销是否按消费者实际生效日期,价格是否为净成交口径,库存是否反映当周可售状态
  2. 画因果路径:明确变量是媒体前的混杂、媒体后的中介,还是潜在碰撞变量,并写清要估计总效应还是直接效应
  3. 做嵌套模型比较:从不含变量的基线模型开始,依次加入促销、价格、库存,记录 Holdout 和滚动回测变化
  4. 检查归因稳定性:比较加入变量前后渠道系数、ROI 区间和排序;大幅变化不是自动说明新版更对,而是提示旧模型存在混杂或新变量在抢解释权
  5. 做合理设定敏感性:更换促销强度口径、价格指数权重、缺货阈值,核心结论不应只在一个任意定义下成立
  6. 用实验校准高风险渠道:如果促销与媒体几乎永远同步,仅靠观测数据很难拆分,需通过 GeoLift、平台 Lift 或刻意制造花费变化获得额外识别

示例:ROI 如何被重新分配

下面是用于说明机制的示例,不代表真实客户或 SparkX 基准。模型使用同一份周度数据,仅逐步增加业务信息:

模型Meta ROISearch ROIHoldout MAPE解释
仅媒体 + 季节性4.16.019%大促增长大量归给同期广告
+ 促销强度 + 价格指数2.94.513%折扣和价格效应从媒体贡献中分离
+ 可售率 + 促销后 lag3.24.611%缺货期需求受限与促销后回落得到解释

最终模型里 Meta ROI 比第二版略高,不矛盾:控制缺货后,模型认识到部分高花费周销售没有继续上涨是供给受限,而不是媒体失效。这个例子说明控制变量不会只把 ROI 往下调;它们的作用是把不同业务机制分开,方向取决于数据和因果结构。

五个常见错误

Q4 建模前检查清单

上传数据之前,先确认
  • 促销字段能区分是否发生、折扣深度、活动类型和业务覆盖率
  • 价格使用实际成交口径,并尽量控制产品组合与币种变化
  • 库存使用可售率或缺货时长,而不只是粗粒度 0/1 标签
  • 促销、价格、库存与媒体数据采用一致时区、周起始日和财务口径
  • 每个变量都画过因果路径,明确它是混杂、中介、碰撞变量还是结果代理
  • 模型比较采用冻结的时间 Holdout 和滚动回测,没有用同一测试窗口反复调参
  • 对媒体与促销长期同步的渠道安排增量实验,或采用小步预算调整验证
  • 严重缺货期的 ROI 和响应曲线明确标注供给约束,不做激进外推

广告 ROI 被高估或低估,很多时候不是建模引擎不够复杂,而是模型没有看到真实业务同时发生了什么。促销决定购买理由,价格改变需求强度,库存决定需求能否兑现。把三者放进正确的因果位置,再用样本外验证和实验校准检查结论,才有资格把模型输出交给预算优化器。

← 上一篇
你的 MMM 模型真的准吗?从 Holdout、滚动回测到归因验证
返回博客 →
所有文章

本站使用 Cookie 和类似技术以提升体验并分析流量。继续浏览即表示同意。详见隐私政策。