P paper2skillsPlaybook
AI 路线图 →

Ad Spend Time Series Attribution — Adstock 衰减 + 因果 MMM 广告效果归因

Skill-Ad-Spend-Time-Series-Attribution · 13-广告分析

causalexperimentforecastingoptimization广告与投放WF-B 广告优化WF-D 选品扫描WF-L 内容营销增长
年化 ROI20-80 万元
实现难度⭐⭐⭐☆☆
业务优先级⭐⭐⭐⭐⭐
业务视角
适用角色广告优化师 / 投放负责人 · CMO · 运营负责人
适用平台Amazon PPC(SP/SB/SD)· TikTok Ads · Meta 广告 · 多平台归因
什么情况下用广告账户几十个系列,不知道哪个在真正赚钱;ROAS 看起来好看但实际利润没有提升;预算有限想集中打高价值用户
成功是什么样的每分广告预算有明确 ROI 追踪,砍掉低效渠道后同等预算 ROAS 提升 30-50%
业务痛点
ROAS 好看但利润没有涨不知道哪个素材真的有效归因窗口期不同数据打架TikTok/Meta/Amazon 广告数据整合不了

1. 解决的问题

母婴跨境运营黑五大促后不知道广告效果是当周还是前 6 周积累所致,导致次日关停广告恰是最高 ROI 时段——Adstock 时序衰减模型识别各渠道 carryover 窗口,ROAS 计算准确率提升 40%,年化避免错误关停损失 20-80 万元

2. 核心算法逻辑

广告投放存在强烈的时序滞后效应(carryover effect):今天曝光的广告可能要 26 周后才完成最终转化。传统 LastClick 或周级 ROAS 完全忽略这一现象,导致大促后关停广告的决策恰好在 ROI 最高时段。

3. 业务应用场景

场景A:黑五大促 Adstock 衰减率估算(防错误关停)

- 业务问题:Momcozy 吸奶器每年黑五前 6 周在 TikTok/Amazon DSP/Google 全面铺量。大促结束次日 ROAS 数据回落,运营关停广告;但实际上前 6 周曝光的 carryover 效应在接下来 3-4 周仍持续驱动自然转化,关停导致年化损失 20-80 万元。 - 数据要求:8 周以上的渠道级周度投放金额 + 周度销售额(SKU 级),共 3-5 个渠道 - 预期产出:每个渠道的 λ(衰减率)、饱和阈值 β、当周真实贡献 vs. 累计 carryover 贡献拆分 - 业务价值:ROAS 计算准确率提升 40%,大促后正确延续投放窗口 2-3 周,年化增收 20

- 业务问题:手握 TikTok/Amazon/Google 三条渠道,预算 50 万,历史数据显示 TikTok 当周 ROAS 低但大促期间 Halo 效应明显,如何分配 Q4 预算? - 数据要求:同上 + 促销节点标记(Prime Day、黑五、圣诞) - 预期产出:基于学习到的 λ 和饱和曲线,模拟 10 种预算分配方案的预期总销售额,输出 Pareto 最优方案 - 业务价值:在相同预算下销售额提升 8-15%,Q4 增量约 15-40 万元

4. 输入数据要求

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

5. 输出结果

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

6. 业务价值 / ROI

  • ROI 预估:ROAS 计算准确率提升 40%,大促后正确延续投放窗口 2-3 周,年化增收 20-80 万元(以 Momcozy 年广告预算 500 万元为基准,0.5% 效率提升即 = 2.5 万元)
  • 实施难度:⭐⭐⭐☆☆(主要难点在历史数据清洗和渠道级日/周度归因粒度对齐)
  • 优先级:⭐⭐⭐⭐⭐(黑五等大促期广告策略直接影响年度 P&L 的关键路径)
  • 适用规模:月广告预算 ≥ 30 万元,3 个以上渠道,历史数据 ≥ 8 周
  • 数据要求:渠道级周度花费 + SKU 级周度销售额(可从广告后台 + 财务系统导出)

7. 代码模板

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

"""
Ad Spend Time Series Attribution with Adstock + Hill Saturation + Simple MMM
场景: Momcozy 吸奶器 8 周三渠道广告数据归因
依赖: numpy, scipy (标准库,无需 deepcausalmmm)
"""
import numpy as np
from scipy.optimize import minimize
from scipy.stats import pearsonr

# ─────────────────────────────────────────
# 核心组件 1: Adstock 几何衰减
# ─────────────────────────────────────────

def adstock_transform(spend: np.ndarray, decay: float) -> np.ndarray:
    """
    Adstock 几何衰减变换
    
    Args:
        spend: 周度投放金额数组 shape=(T,)
        decay: 衰减率 λ ∈ [0, 1],越大持续越久
    
    Returns:
        adstocked: 衰减后的有效曝光数组 shape=(T,)
    """
    T = len(spend)
    adstocked = np.zeros(T)
    adstocked[0] = spend[0]
    for t in range(1, T):
        adstocked[t] = spend[t] + decay * adstocked[t - 1]
    return adstocked


# ─────────────────────────────────────────
# 核心组件 2: Hill 饱和曲线
# ─────────────────────────────────────────

def hill_saturation(x: np.ndarray, alpha: float, beta: float) -> np.ndarray:
    """
    Hill 饱和曲线,捕捉边际递减效应
    
    Args:
        x: 输入投放量(已 Adstock 变换后)
        alpha: 形状参数 (>0),控制 S 型曲线斜率
        beta: 半饱和点 (>0),x=beta 时 Hill=0.5
    
    Returns:
        saturated: 饱和后效果值 ∈ [0, 1)
    """
    x_alpha = np.power(np.maximum(x, 1e-10), alpha)
    beta_alpha = np.power(beta, alpha)
    return x_alpha / (x_alpha + beta_alpha)


# ─────────────────────────────────────────
# 核心组件 3: 简化 MMM 模型(OLS)
# ─────────────────────────────────────────

class SimpleMMM:
    """
    简化版 Marketing Mix Model

8. 论文来源

  • 2510.13087