资讯详情

资讯详情

营销活动因果影响分析:从归因模型到增量价值评估

做营销数据分析的人十有八九都遇到过同一个问题老板拿着报表问“这个月GMV涨了10%到底是哪条渠道投得值”然后你打开后台把各个渠道的转化数据一拉发现线索率最高的渠道花了80%的预算但销量贡献占比却只有30%。于是你开始怀疑人生这些预算到底该往哪投更尴尬的是你把某条广告停掉之后整体转化反而涨了——眼看着预算省了业绩没掉你才意识到之前看到的“渠道贡献”全是错觉。这个问题的本质不是报表算错了而是你一直在衡量相关关系而不是因果关系。标题里那句“衡量你市场营销活动的内在因果影响”说的就是这么回事我们要回答的问题不是“看了广告的人有没有买”而是“如果没有这条广告他们会不会照样买”只有搞清楚这个“如果没有”才能算清楚一条渠道、一次活动真正的增量价值。这篇文章我就围绕“因果影响”这个核心把我在营销活动分析上踩过的坑、用过的套路、跑通的方法论完整拆开讲。内容包括为什么传统归因模型靠不住、因果推断的几种主流方法怎么选、一套可以落地的实操流程以及那些你看文档绝对学不到的排查经验和避坑技巧。适合正在做营销分析、用户增长、广告投放优化的同学参考也适合被“归因不准”折磨到怀疑人生的运营朋友。1. 为什么传统归因工具衡量不了“因果”1.1 归因模型只能回答“钱花哪了”回答不了“钱该不该花”现在市面上所有主流的归因模型从末次点击、首次点击、线性归因、时间衰减到基于算法的Shapley值归因本质上都在做同一件事把一次成交拆解到多个触点上去算每个渠道“分”了多少功劳。这套逻辑在追踪体系健全的电商场景下确实够用但它的成立前提是所有有影响的触点都能被记录到。现实情况远没有这么理想。用户可能在刷短视频时看到你的信息流广告没有点击但记住了品牌第二天自己去搜索引擎里搜你的产品关键词然后从自然搜索链接点进来下单。在传统归因模型里这笔订单可能会被记到“自然搜索”头上信息流广告因为“未被点击”完全没有记录。但你要真把信息流广告停掉一个月后自然搜索的转化量大概率也会跟着掉——只是系统根本测不出这个联动关系。所以说归因模型回答的问题始终是“功劳归谁”而不是“如果砍掉这条渠道结果会差多少”。后者才是因果问题。因果问题的核心表述永远是反事实的不投这条广告的对照组和投了广告的处理组相比结果差了多少归因工具的数据结构不允许你构建这个对照组所以无论模型多高级算法多花哨都跨不过这道坎。1.2 相关性陷阱两个看起来强相关的指标可能毫无因果关系我踩过最典型的一个坑是这样的某次大促活动上线后我们观察到老用户复购率明显上升同时新客转化率也在涨两个指标的相关性系数高达0.82于是运营团队认定活动设计很成功“老带新”策略发挥了大作用。后来我们把数据按时间拉长看发现那个月整个行业的用户活跃度都在上涨因为正好赶上消费旺季全民购物意愿本身就高。这是一个标准的混淆变量问题季节趋势同时影响了复购率和新客转化率让两个指标“显得”存在因果关系实际上它们只是同一根藤上结的两个瓜。营销领域到处是这样的虚假相关。比如投放预算增加的同时用户留存率也上升了背后可能是产品本身发了一个爆款版本广告点击率上升的同时客单价也上升了背后可能是你偷偷把低客单价的商品下架了。要识别这类陷阱靠观测数据本身是不可能完成的必须引入实验设计或者准实验方法对掉时间趋势、季节因素、产品变化等各类混淆项的影响才能把真正属于“营销活动”的增量部分剥离出来。这也是因果推断整套方法论存在的根本原因。2. 因果推断的核心方法选型2.1 黄金标准随机对照实验A/B测试到底好在哪因果推断领域的黄金标准是随机对照实验放在营销场景里就是A/B测试。核心逻辑很容易理解你有一万个目标用户随机分成两组一组看到你的新广告处理组一组看老广告或者什么都不看对照组。因为随机分配两组用户在年龄、地域、消费历史、兴趣爱好等所有维度上的分布基本一致唯一的差别就是“看没看新广告”。这样一来实验结束后两组之间的转化率差异就只能归因于广告本身。这套逻辑的威力在于它自动化地解决了所有混淆变量的问题。你不用拿数据去“控制”用户的年龄差异、消费习惯差异随机化替你把这些差异全抹平了处理组和对照组在统计上就是两个完全相同的人群。我在实际项目里感受特别明显前面做观测数据分析时光清洗数据、调配权重、跑匹配模型就要花一周做A/B测试的话设计好分流逻辑上线等数据量够了直接算显著性就行分析部分轻松很多。但A/B测试也有严格的前提实验必须跑在可控的流量场景里。很多营销活动天然不具备这个条件。比如你做了个线下快闪店、投了电视开机广告、上了几个头部主播的直播间这种覆盖小范围人群的活动根本没法做严格的随机分组。就算能做分组用户也可能互相讨论、互相影响破坏随机分配的有效性。这种情况下就得靠观测数据类的因果推断方法兜底。2.2 观测数据救场倾向得分匹配、双重差分、断点回归怎么选当实验设计不可行时我们就要从历史观测数据里想办法构造一个“伪对照组”。核心思路是虽然没有随机分组但我们可以试着找到一组“看起来”和活动触达人群很像、但实际没有被活动触达的用户用他们来模拟反事实结果。我用的最多的方法是倾向得分匹配Propensity Score MatchingPSM。核心思想是把用户的所有历史特征年龄、消费频次、登录活跃度、渠道来源、历史客单价等送入一个模型计算出每个用户“被活动触达的概率”倾向得分然后给每个处理组用户匹配一个倾向得分最接近的未触达用户构造出对照组。匹配完以后两组之间的转化差异就可以近似视为活动的影响。双重差分法Difference-in-DifferencesDID则是从时间维度找答案的思路。假设你有一条广告只在华东地区投放了华北地区没有投。你可以取华东地区投放前后的销量差再减去华北地区投放前后的销量差两个差值相减之后就能把“两个地区共同存在的趋势性变化”比如全行业上涨或下跌减掉剩下的就是广告带来的增量效果。这个方法不需要用户级别的匹配只需要区域级别的数据就能跑。断点回归Regression DiscontinuityRD在营销里用得相对少一点但在特殊场景下非常有效。比如某个活动只对消费满500元以上的用户发放高额优惠券那么499元和501元的用户理论上没有本质差异但一边能领券一边不能领这种“断点”附近人群的差异就可以被用来估计优惠券的真实拉动效果。三个方法的适用场景我整理成一张表放在下面方法数据需求核心假设最适用场景A/B测试实验设计能力随机分组有效线上广告、页面改版、Push文案测试倾向得分匹配用户级明细数据无未观测到的混淆变量活动人群与未触达人群存在系统性差异双重差分区域/时间面板数据处理组与对照组趋势平行区域定向投放、分城市试点活动断点回归精确的门槛划分规则断点附近个体可互换满减门槛、会员等级、优惠券准入门槛2.3 方法选型的决策逻辑别一上来就上复杂模型选方法的时候要克制不要觉得模型越复杂越好。我见过很多团队一上来就要跑机器学习模型但连基础的对照组都没设计清楚。选型的判断顺序应该是先问能不能做A/B实验能做就优先做做不了再退一步看是否有明确的分区、分时段投放记录有就用双重差分分区信息也没有就退到用户级的数据用倾向得分匹配如果手上只有某个断点规则的数据就上断点回归。这个顺序的核心逻辑是从数据因果性最强的设计到最弱的设计逐级退让。实验设计的因果推断能力最强因为它唯一地确定了反事实观测数据方法因果推断能力弱因为每一步都要靠敏感且脆弱的假设去撑。能上强度大的就不要用弱势方法凑合。这跟你买东西一个道理能买正版就别用盗版能上原装就别拿兼容件凑数。实操中还经常出现一种混合情况团队做了A/B实验但实验漏掉了某些渠道或者活动不是一次性全量发的而是分批发放的这种情况下可以把A/B结果作为校准基准再用观测数据方法补足实验覆盖不到的维度。先保证主方法的因果有效性再用辅助方法补充覆盖面这也是完整测量体系里很重要的一环。3. 实操过程从数据准备到影响度量3.1 第一步梳理活动事件流与数据口径动手跑任何因果模型之前先花一整天把数据底表理清楚。这一步偷懒后面所有环节都会翻车。我在实际项目里做的第一件事是拉出活动相关的事件流清单活动曝光事件、点击事件、加购事件、领取优惠券事件、下单事件、支付成功事件。然后明确每张表的粒度。事件流水表通常一行一个用户行为订单表一行一个订单用户信息表一行一个用户。做因果推断之前必须把粒度统一到用户级别否则后面算出来的倾向得分就是乱的。这里推荐的做法是建一张以用户ID为主键的宽表把用户特征、活动曝光、行为转化、订单结果一次性全部拼进去。拼表时特别容易忽略时间窗对齐。活动参与事件和转化事件之间要设定合理的转化窗口窗口太短会漏掉后置转化窗口太长又容易混入用户自然转化。不同品类的决策周期完全不同低价日用品可能三天就复购了高价耐用品可能一个月都在比价。我在电商项目里通常会取活动结束后7天作为短窗口、30天作为长窗口分别计算最后看两个口径的结果是否一致一致性高说明结果稳健。还有一点要注意数据质量用户ID跨端统一了吗同一用户在不同设备上的行为是不是被记成了两个ID优惠券核销状态有没有更新延迟这些脏数据问题在清洗阶段不解决后面的因果模型跑出来的结果根本不值得信。3.2 第二步定义处理组、对照组与核心结果指标处理组的定义通常不复杂标记出“在活动期间实际触达的用户”。但这里有个隐藏问题用户触达不等于用户看到。放在信息流场景里曝光一次算不算触达我的经验是设置一个最低曝光阈值比如在活动周期内至少曝光3次以上才计入处理组低于这个曝光的用户视为未真正触达丢到待选池里。对照组怎么选是整个分析中争议最大的部分。很多人图省事直接把活动期间“没有曝光”的用户全部当作对照组这绝对不行。这些用户跟处理组用户截然不同他们可能是低频不活跃用户可能根本对产品没兴趣他们的转化率天然就比高活跃用户低很多直接比较会严重低估活动效果。这里就需要用到上面说的倾向得分匹配了。先把处理组和候选对照组的用户特征全部取出来特征我一般固定用这几个最近30天登录天数、历史总消费金额、历史订单数、平均客单价、最近一次购买距今多少天、主要来源渠道、用户等级。跑一个逻辑回归因变量是“是否被活动触达”特征就是上面那些变量每个用户算出一个倾向得分。匹配算法我常用的是把倾向得分控制在0.01之内的最近邻匹配或者用卡尺匹配加放回抽取。匹配完以后要检查标准化均值差处理组和对照组在核心特征上的标准化均值差应在±0.1以内说明匹配效果合格如果某些特征差得离谱说明倾向得分模型漏了重要变量得回头补特征再跑一遍。这一步是决定整个分析可信度的关键。核心结果指标的选择同样重要。我的建议是至少包含两层指标第一层是转化类指标比如购买转化率、人均订单数第二层是价值类指标比如人均GMV、人均毛利。只看转化率会忽略客单价差异只看GMV会被大额订单拉偏。两层指标放一起看才能全面判断活动真正“带去”了什么价值。3.3 第三步模型实现与参数计算附关键配置下面用一个实际的建模过程来说明具体怎么跑。假设我要分析的是“某穿搭App上的一次新人专享立减活动”处理组是活动期间通过首页Banner首次领取新人券并完成注册的用户对照组候选池是全站未参与该活动的同周期新注册用户。特征工程阶段我建了这么一批特征注册距今的天数、注册前7天浏览商品详情页次数、注册频道来源自然搜索/推荐/外部推广/直接访问、注册后是否填写偏好标签、首单之前是否发起过客服咨询、历史登录设备品牌区分iOS/Android。特征不要求多要求精每个特征都得跟“活跃度”和“消费意愿”高度相关。逻辑回归的代码结构大概是这样的基于Python的sklearn和statsmodels库import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler import numpy as np # 读取宽表数据 df pd.read_csv(campaign_user_level.csv) # 处理组标记1为触达活动0为候选对照组 features [reg_days, detail_views, channel, has_interest_tag, has_consult, device_type] X pd.get_dummies(df[features], drop_firstTrue) y df[treated] # 标准化连续特征 scaler StandardScaler() X[[reg_days, detail_views]] scaler.fit_transform( X[[reg_days, detail_views]]) # 训练倾向得分模型 ps_model LogisticRegression(max_iter1000, C0.1) ps_model.fit(X, y) df[propensity] ps_model.predict_proba(X)[:, 1]这里有个参数要特别说明逻辑回归的正则化系数C我选了0.1而不是默认的1.0。原因是营销活动的处理组与对照组差异通常非常大默认正则化下倾向得分会迅速被少数强特征主导导致后续匹配不稳定。调小C增加正则化强度能够让倾向得分分布更平滑匹配效果更好。这是一个实际调参中摸索出来的经验不是教科书上的标准答案但实测下来很稳。逻辑回归训练完之后进入匹配环节。先给处理组每个用户找一个倾向得分最接近的对照组用户。为了保证匹配质量我用了卡尺匹配设定卡尺宽度为0.05同时对匹配权重做了限制。from sklearn.neighbors import NearestNeighbors treated df[df[treated] 1] control_pool df[df[treated] 0] # 对处理组用户在对照组池中寻找倾向得分最近的样本 nn NearestNeighbors(n_neighbors1, metriceuclidean) nn.fit(control_pool[[propensity]]) distances, indices nn.kneighbors(treated[[propensity]]) # 取卡尺范围内的匹配样本 matched [] for i, (dist, idx) in enumerate(zip(distances, indices)): if dist[0] 0.05: matched.append({ treated_id: treated.iloc[i][user_id], control_id: control_pool.iloc[idx[0]][user_id], dist: dist[0] }) matched_df pd.DataFrame(matched)匹配完之后一定不能急着算结果。先做均衡性检验也就是标准化均值差SMD的检查。我的经验判别线是SMD小于0.1就算合格小于0.05是优秀。如果核心特征上SMD超标说明倾向得分模型拟合不充分通常处理方法是加入交互项、增加非线性变换或换用随机森林来估计倾向得分。均衡性检验通过后计算处理效应。这里用的是平均处理效应中的已处理组效应ATT表示“对于实际触达活动的这些用户相对如果他们没触达活动平均每人多产生了多少转化价值”# 计算ATT conversion_treated treated[conversion].mean() conversion_control matched_df.merge( control_pool, left_oncontrol_id, right_onuser_id )[conversion].mean() att_conversion conversion_treated - conversion_control gmv_treated treated[gmv].mean() gmv_control matched_df.merge( control_pool, left_oncontrol_id, right_onuser_id )[gmv].mean() att_gmv gmv_treated - gmv_control print(f转化率ATT {att_conversion:.4f}) print(f人均GMV的ATT {att_gmv:.2f}元)跑完这两行之后你会看到活动真实的增量价值。注意是增量不是绝对值。比如活动页面整体转化率是8%但匹配后的对照组转化率是6.5%那活动的因果影响就只有1.5个百分点而不是8个百分点。这1.5个百分点才是你投广告、做活动真正买来的东西。还要补充一种情况如果你手里正确分区域的投放数据比如A城市投了、B城市没投那么用双重差分法会更省事。DID的训练代码本质上就是跑一个固定效应回归模型import statsmodels.formula.api as smf # did_data: city, time(投放前/后), treated(是否投放城市), gmv did_model smf.ols( gmv ~ treated time treated:time, datadid_data ).fit() print(did_model.params[treated:time]) print(did_model.pvalues[treated:time])交叉项的系数就是投放城市相比未投放城市在投放前后GMV变化的差异即活动的因果效应。p值小于0.05才能说效应显著不然就只是随机波动不能下结论。3.4 第四步结果解读与稳健性检验跑完模型拿到ATT只是起点离“能向老板汇报”还差几步。我拿到结论后首先会看方向对不对、量级合不合理。如果算出活动的增量转化率是20个百分点基本不用想了肯定哪里出了问题这种量级在成熟品类里几乎不可能出现。合理区间大概率在1到5个百分点之间。量级离谱的时候先去查匹配是否引入极端样本再去查倾向得分分布是否严重失衡。接下来做稳健性检验。最常规的做法是换匹配参数、换转化窗口、换样本范围。我在项目里会跑三个版本的稳健性测试第一版用卡尺0.05最近邻匹配第二版用卡尺0.1带替换匹配第三版直接用不加匹配的回归调整法把倾向得分本身作为协变量放入线性回归。三个版本量级一致、方向一致说明结论可信如果三个版本差出一个量级说明对方法和参数极其敏感此时不要急于下结论。最后一步是把因果分析结果和传统归因模型的结果并排放在一起对比。这两者之间的差异往往是最有价值的汇报素材。传统归因告诉你的是一次活动“表面贡献”有多高因果推断告诉你“增量贡献”有多高。两者差距越小说明渠道自然转化越少投放价值越被低估差距越大说明渠道引流大部分是捡了自然流量的漏预算效率堪忧。这份并排对比表是给决策层看的最好素材指标本身直接对应预算调整的取舍。4. 常见问题与排查技巧实录4.1 问题一处理组和对照组样本量差距太大怎么办运营活动中经常出现处理组几万人、对照组几十万人的情况样本比例严重失衡。直接做倾向得分匹配有个问题由于分布重叠区域有限会有一大堆对照组用户完全匹配不上处理组白白浪费数据。我的处理方式是分两步走先在对照组池里做一次粗筛只保留与处理组核心特征比如历史消费频次、用户活跃等级、注册时间范围相近的子集再在这个子集上做精确的倾向得分匹配。粗筛直接把两个人群拉近后续匹配效率和精度都会明显提升。如果粗筛之后还是不够可以考虑下沉一级不做用户级别匹配改成渠道级别或者城市级别的DID分析。粒度粗了样本量自然就大了分析稳定性更好代价是因果结论的颗粒度变粗。一定要记住样本不够宁可换更粗粒度的方法也不要强行在样本稀疏时跑复杂模型否则结果就是一堆数字在骗自己。4.2 问题二自助归因中的“溢出效应”污染了对照组这是做A/B测试或者区域对照时特别容易忽略的一个问题。假设你给A组用户投放了广告A组用户中的某个人转发给了没投放的B组用户B组用户也下单了那B组的转化里其实混入了A组广告的影响。这样一来处理组和对照组的差异就被抹平了因果效应被系统性低估。这个问题在社交属性强的品类的特别严重微信生态里的裂变活动、拼团玩法都在主动制造这种组间污染。解决方式首先是尽量选择独立性质强的单元做实验比如用城市做随机化单元用户跨城市流动概率会自然降低。其次是如果只能用户级随机就要在解读结果时对溢出效应的方向有预判知道真实效应可能比自己测出来的高给决策留出安全边际。4.3 问题三活动之前的趋势差异就很大DID结果不可信DID方法的核心假设是要“平行趋势”投放组和对照组在活动前就已经保持相同的增长或者下降趋势。很多时候这个假设不满足。比如你选了华东做投放华东本身市场增速远高于华北那即便这个活动完全无效DID也会算出一个正效应因为两组趋势本来就不平行。排查手段说来也简单拉出投放前12个月的月度GMV序列画出两条线看趋势是否平行。视觉上不好判断的话可以跑一个“安慰剂检验”把投放时间虚拟提前三个月重新跑DID。如果提前三个月也能跑出显著的“效应”说明基本趋势压根不平行当前结果的因果性就要打问号。我做过最虚的项目就是在安慰剂检验暴露出明显问题之后果断放弃DID改用了PSM。4.4 常见问题速查表症状可能原因排查方法解决方案ATT为负且巨大遗漏了与活跃度负相关的关键特征查均衡性SMD是否超高增加特征、换倾向得分模型匹配后样本骤减卡尺过窄、样本重叠区域不足看倾向得分分布图放宽卡尺、先做粗筛稳健性检验方向不一致转化窗口选择不当对比7日/30日结果以业务周期为准重设窗口DID结果显著但安慰剂检验也显著平行趋势不成立虚设活动时间重跑换PSM或细分人群全渠道归因和因果分析差距过大存在大量站外触达未追踪对比流量来源完整性补站外监测、正视追踪盲区4.5 几条宁可绕路也要避开的坑第一不要拿活动期间的购买用户去反推因果。很多人图方便取出活动期间下单的用户直接看他们触达哪些渠道这个过程中把“买了之后的人”当成“因变量”来统计是对数据逻辑的倒错。因果问题的起点是触达与未触达的对比不是下单用户的渠道构成。第二不要在数据清洗阶段把转化率低到离谱的渠道清理掉。清理异常值时要区分“数据垃圾”和“真实信号”。有些渠道转化确实很低但它可能覆盖的是高价值用户对购买转化没贡献对品牌搜索有巨大拉动。你一把它洗掉后面的因果分析就缺了一个关键解释变量。第三不要在下发活动需求之前不定义评估口径。活动开始前就应该明确三件事谁算触达、谁算未触达、转化窗口多长。这三件事如果在活动结束后才拍脑袋定就永远有个“事后找数据”的嫌疑分析结果也容易被业务方挑战不好收场。5. 从“衡量因果”到“优化决策”的落地经验我做完一套完整的营销活动因果影响分析之后习惯把结果输出成一张“决策表”。表里只留三列活动/渠道名称、增量收益以GMV或毛利计、增量率相对对照组。决策表发下去之后不再需要跟业务团队解释“贡献”和“增量”的区别所有人看到数字心里都有数。有一次做出一个很有意思的结果一个用“高折扣限时抢购”玩法留存老客的活动传统归因显示这个活动贡献了20%的当日GMV但因果分析算下来增量只有2个百分点说明大部分下单用户本来就要买活动只是在收割存量需求。另一个不起眼的“新品内容种草”活动反而增量显著触达用户相比未触达用户的新品购买率高出一大截。最终我们调整了预算配比砍掉高折扣预算把资源挪到内容种草上次月整体新品销售利润反而涨了。这个案例说明一个道理营销活动因果衡量的终极目的不是写分析报告而是做预算重分配的依据。通过衡量增量影响把预算配置到真正能拉动增量的地方砍掉那些只是“看起来数据很好”的活动整个营销ROI才能实质性改善。这也是我会建议所有做营销分析的人一定要掌握因果推断的原因——它不只是数据分析技能更是预算博弈桌上最硬的筹码。我个人实际操作的体会是不要追求一步到位部署完整的多触点因果归因平台就从手头一个最关心的活动开始按照文中的流程把PSM或DID跑通。第一版先看方向对不对方向对了再逐步推广到全部渠道。不要急着把工具做复杂复杂的衡量体系建立在一次一次单点活动的准确度量之上单点不准体系再大也是白搭。如果你手头正好有个刚做完或者正在策划的营销活动我建议你认真想想这个活动如果不做会发生什么想清楚这个问题你对因果衡量的理解就及格了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →