paper2skills Playbook

Identified Bayesian MMM — 基于高斯过程的无混淆贝叶斯营销归因

Skill-Identified-Bayesian-MMM · 15-营销投放分析

causalexperimentforecastingoptimizationfraud_detection广告与投放定价与利润风控与合规WF-B 广告优化WF-D 选品扫描
年化 ROI1000 万元
实现难度⭐⭐☆☆☆
业务视角
适用角色CMO / 营销负责人 · 广告优化师 · CEO
适用平台Amazon + TikTok + Meta + KOL 四渠道 · Prime Day / Black Friday 预算前置
什么情况下用同时跑 Amazon 广告/TikTok/网红投放/邮件,不知道整体预算怎么分配最高效;网红投放花了大钱但不知道带来多少真实 GMV
成功是什么样的建立全渠道营销归因模型(MMM),每个渠道真实 ROI 可量化,大促前做预算优化模拟
业务痛点
多渠道预算分配靠感觉网红带货效果不知道怎么量化渠道之间互相抢功劳数据打架整体营销 ROI 算不清楚

1. 解决的问题

CMO 拿到内部 MMM 报告,显示"TikTok ROAS 极高远未饱和,建议把 Meta 预算砍半全移给 TikTok"

2. 核心算法逻辑

传统开源 MMM(Robyn / Meridian)在仅有平稳投放数据时,会陷入一个数学死结:非线性饱和效应(spend 越多边际回报越低) 与 时变效应(节假日转化本就更好) 在数学上"观测等价"——两个完全不同的数据生成过程可以产生完全相同的观测值。这意味着模型给出的 ROAS 可能是系统性偏差的,据此做的预算决策会踩坑。

3. 业务应用场景

- 业务问题:CMO 拿到内部 MMM 报告,显示"TikTok ROAS 极高远未饱和,建议把 Meta 预算砍半全移给 TikTok"。过去半年 TikTok 均匀花出,数据平稳,但心里极没底——不知道高 ROAS 究竟是因为渠道牛还是碰上了旺季。 - 数据要求: - 90 天以上的日级三渠道(Google / Meta / TikTok)spend + conversions 数据 - 每渠道至少一次关停或超投实验记录(期间、倍率、实测提升比) - 操作路径: 1. `mmm.diagnose()` 输出诊断报告,TikTok 被标为 HIGH RISK,附实验处方 2. 按处方在德州区

- 业务问题:品牌方希望在 618 前确认 Google Shopping 当前是否还有边际 ROAS 空间,还是已经深度饱和,不该再加仓。 - 数据要求: - 近 60 天 Google 日级 spend + 转化数据 - 过去 2–3 次周末/节促期间的超投记录(自然发生的预算脉冲也算) - 操作路径: 1. 仅用 Google 渠道数据初始化 `IdentifiedBayesianMMM` 2. 若历史峰谷比 ≥ 2×,直接 `fit()` 即可;若平稳则补充一次测试性周末超投 3. 调用 `gp.predict(spend_query)` 绘制完整饱和曲线,`gp.marginal_r

4. 输入数据要求

请查看原始代码模板获取输入规格。

5. 输出结果

请查看原始代码模板获取输出规格。

6. 业务价值 / ROI

  • ROI 预估
  • 实验成本:2 天局部区域(约 5% 流量)的停投损失,约 0.5–2 万元
  • 保护价值:避免年度预算误分配,中型品牌(年广告 1000 万元)潜在年化收益 100–500 万元
  • 投入产出比:保守估算 50–250 倍
  • 实施难度:⭐⭐☆☆☆(2/5)
  • 数学部分已封装,业务侧主要难点在于推动团队执行关停实验(需跨部门协调)

7. 代码模板

代码块数量:1 · 路径:未检测到

"""
使用方法示例: Identified Bayesian MMM 三渠道归因与预算优化
依赖: numpy (已内置于 model.py)
"""
import numpy as np
from model import (
    ChannelData,
    ExperimentalShock,
    IdentifiedBayesianMMM,
)

# --- 1. 准备数据 ---
# 替换为真实数据: pd.DataFrame 按渠道拆分后转 numpy
tiktok = ChannelData(
    name="TikTok",
    spend=np.array([10000] * 90, dtype=float),        # 日投放金额
    conversions=np.array([14500] * 90, dtype=float),  # 日转化金额
)
meta = ChannelData(
    name="Meta",
    spend=np.linspace(5000, 15000, 90),
    conversions=np.linspace(8000, 18000, 90) + np.random.default_rng(0).normal(0, 500, 90),
)
google = ChannelData(
    name="Google",
    spend=np.where(np.arange(90) % 7 >= 5, 20000, 8000).astype(float),
    conversions=np.where(np.arange(90) % 7 >= 5, 28000, 12000).astype(float)
               + np.random.default_rng(1).normal(0, 300, 90),
)

# --- 2. 初始化模型并诊断 ---
mmm = IdentifiedBayesianMMM([tiktok, meta, google])
report = mmm.diagnose()

print("=== 可识别性诊断 ===")
for ch, risk in report.channel_risks.items():
    print(f"  {ch}: {risk}")

if report.experiment_prescriptions:
    print("\n=== 实验处方 ===")
    for p in report.experiment_prescriptions:
        print(f"  {p}")

# --- 3. 录入实验冲击数据(执行实验后填写) ---
# 场景: 第 80-83 天对德州区域停投 TikTok
mmm.add_shock(ExperimentalShock(
    channel="TikTok",
    shock_period=(80, 83),
    spend_multiplier=0.0,   # 完全停投
    observed_lift=0.08,     # 停投后转化跌至基线的 8%(实测数据)
))
# 第 83-86 天同区域超投 3 倍
mmm.add_shock(ExperimentalShock(
    channel="TikTok",
    shock_period=(83, 86),
    spend_multiplier=3.0,
    observed_lift=1.75,     # 转化提升至基线的 1.75 倍(实测数据)
))

# --- 4. 拟合模型 ---

8. 论文来源

  • 2408.07678