Multi-Touch Attribution Modeling for Digital Advertising
Skill-Ad-Attribution-Modeling · 13-广告分析
1. 解决的问题
用户从第一次看到广告到最终下单,平均接触5-7个触点(Facebook视频、Google搜索、TikTok短视频、再营销广告、邮件)。
2. 核心算法逻辑
核心问题:用户从第一次看到广告到最终下单,平均接触57个触点(Facebook视频、Google搜索、TikTok短视频、再营销广告、邮件)。哪个触点真正促成了转化?最后点击(LastClick)模型把功劳全给最后一个触点,严重低估了上层漏斗的价值。
3. 业务应用场景
业务问题:Momcozy 月广告预算50万,分配为Facebook 30万、Google 15万、TikTok 5万。但Last-Click归因显示Google贡献60%转化,Facebook只有25%。团队想砍掉Facebook预算加到Google——这是Last-Click的陷阱。
数据驱动归因分析: 1. 收集用户旅程数据:每个转化的完整触点序列 2. Shapley值计算: - Facebook:边际贡献 38% - Google:边际贡献 32% - TikTok:边际贡献 18% - Email:边际贡献 12% 3. 与Last-Click对比: - Facebook:Last-Click 25% → Shapley 38%(被低估!) - Google:Last-Click 60% → Shapley 32%(被高估!)
决策变化: - 原方案:Facebook 30万 → Google 45万 - 修正后:Facebook 35万、Google 25万、TikTok 15万、Email 5万 - 预期效果:整体ROAS从2.5提升到3.2
4. 输入数据要求
请查看原始代码模板获取输入规格。
5. 输出结果
请查看原始代码模板获取输出规格。
6. 业务价值 / ROI
- ROI:预算重新分配后ROAS提升20-40%,年节省浪费预算10万+
- 难度:⭐⭐⭐☆☆(3/5)— Shapley计算复杂,但规则模型简单
- 优先级:⭐⭐⭐⭐⭐(5/5)— 广告预算分配的前提,没有归因就没有优化
7. 代码模板
代码块数量:1 · 路径:未检测到
"""
Ad Attribution Modeling — 广告归因模型
支持:规则归因、Shapley值、马尔可夫链、移除效应
"""
import numpy as np
import pandas as pd
from itertools import combinations
from collections import defaultdict, Counter
class AttributionModel:
"""广告归因模型"""
def __init__(self, journeys, conversions):
"""
Args:
journeys: list of lists, each inner list is touchpoint sequence
conversions: list of 0/1, whether each journey converted
"""
self.journeys = journeys
self.conversions = conversions
self.channels = sorted(set(c for j in journeys for c in j))
def last_click(self):
"""Last-Click归因"""
attribution = Counter()
for journey, conv in zip(self.journeys, self.conversions):
if conv and journey:
attribution[journey[-1]] += 1
return dict(attribution)
def first_click(self):
"""First-Click归因"""
attribution = Counter()
for journey, conv in zip(self.journeys, self.conversions):
if conv and journey:
attribution[journey[0]] += 1
return dict(attribution)
def linear(self):
"""Linear归因"""
attribution = Counter()
for journey, conv in zip(self.journeys, self.conversions):
if conv and journey:
for ch in journey:
attribution[ch] += 1 / len(journey)
return dict(attribution)
def position_based(self, first_weight=0.4, last_weight=0.4):
"""Position-Based归因"""
attribution = Counter()
for journey, conv in zip(self.journeys, self.conversions):
if not conv or not journey:
continue
n = len(journey)
if n == 1:
attribution[journey[0]] += 1
elif n == 2:
attribution[journey[0]] += first_weight
8. 论文来源
未自动抽取;请查看原始 Skill 卡片。