ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

因果模型入门:从DAG、do算子到DoWhy与EconML实战

因果模型入门:从DAG、do算子到DoWhy与EconML实战 1. 因果模型到底解决什么问题从一次翻车的增长实验说起因果模型这个词这几年在数据圈子里出现得越来越频繁但很多人第一次接触它是因为一次不太好看的复盘。我印象很深的一次某个功能上线后大盘留存涨了 3 个点团队兴高采烈地写了复盘报告结果第二周指标又掉回去了。后来才发现那批被新功能影响的用户本身就是活跃度更高的一群人他们无论有没有新功能都会留下来。这就是因果模型要处理的核心问题我们观测到的关联到底有多少是真正的因果效应有多少只是选择偏差和混杂因素制造的幻觉。因果模型Causal Model本质上是一套描述变量之间因果作用机制的数学与图形语言。它要回答的不是X 和 Y 是否一起变化而是如果我把 X 拨动一下Y 会变成什么样。前者是统计学里的相关问题后者是干预问题。这两者之间的差距就是 Judea Pearl 说的因果之梯的第一级和第二级之间的鸿沟。而再往上一层是反事实问题——对于这个已经发生的结果如果当初做了另一个选择会怎样。这篇文章面向的是刚接触因果模型、但已经有一定数据分析和机器学习基础的人。你可能是做推荐、增长、风控、医疗分析、运营策略的数据同学也可能是想把因果思路用到产品决策上的业务负责人。我会把因果模型的骨架拆开讲清楚给出一个能直接跑通的实操流程再把我自己在真实项目里踩过的坑整理出来。读完之后你至少能做到三件事看懂一篇因果推断论文在讲什么、判断一个业务问题该不该用因果方法、以及用 Python 跑出一份带反驳检验的因果效应估计报告。2. 学因果模型之前必须搞清楚的核心概念2.1 从相关到因果要跨过的三道坎第一道坎是混杂。举个生活化的例子冰淇淋销量和溺水人数高度正相关但不是冰淇淋导致溺水而是夏天这个共同原因同时推高了两个变量。在业务里这个夏天可能是用户活跃度、季节、渠道质量、大促节奏。只要混杂因子没有被控制住你算出来的任何相关性都会被污染。混杂的特点是它同时影响处理变量是否接受干预和结果变量这条后门路径会把真实因果效应和虚假关联混在一起。第二道坎是选择偏差。我们能观测到的样本往往不是随机分配的。比如你想评估参加付费课程是否能提升用户留存但愿意付费的用户本来黏性就高。这不是随机实验样本进入处理组的过程本身就带信息。选择偏差和混杂在数学形式上都可以用同一套图语言描述但它们的来源不同混杂来自共同原因选择偏差来自样本筛选机制。第三道坎是反向因果。X 影响 Y还是 Y 影响 X或者两者互为因果形成反馈环在推荐系统里这个问题极其常见用户点击了某个商品系统认为他喜欢于是推更多类似商品用户又点了更多——这个循环里到底哪个是因哪个是果很难从纯观测数据里区分。时间顺序是判断因果的必要条件但在有反馈环的系统里时间顺序本身也会被打破。注意很多团队在做归因分析时默认后发生的就是被影响的这个假设在存在滞后效应和反馈环时几乎必然出错。理解了这三道坎你就能明白为什么因果模型必须引入假设。因果推断从来不是从数据里算出因果关系而是在一组明确假设下把观测分布映射到干预分布。假设是你能拿到什么结论的前提不是可选项。2.2 三大流派各自擅长什么该怎么选因果推断目前主流有三条路线它们不是互相替代的关系而是三种表达方式。流派核心工具表达方式强项典型工具结构因果模型SCM有向无环图、do算子图 结构方程表达机制、识别调整集DoWhy、CausalNex潜在结果框架反事实结果、ATE/CATE随机变量实验设计、效应估计EconML、CausalML工具变量/准实验IV、DID、RDD计量模型无法做实验时的替代linearmodels、statsmodelsSCM 的优势在于把假设画出来。一张 DAG 画完谁是混杂、谁是中介、哪些变量不能控制一目了然。它的短板是对函数形式要求高且图本身错了后面全错。潜在结果框架的优势是定义清晰ATE、ATT、CATE 这些量都有严格的数学定义和各种机器学习模型结合得很自然。它的短板是假设无混杂、正性、SUTVA往往说不清是否成立。准实验方法的优势是能用真实世界政策、阈值、断点来构造近似随机但适用条件苛刻外推性差。选型上我自己的判断逻辑是这样的如果这个问题能做随机实验优先做实验因果模型只用来做实验后的异质性分析和机制分析如果不能做实验但有一张可信的因果图走 SCM 后门调整如果连图都画不出来但有天然的断点或政策冲击走准实验如果都不行那就要坦白告诉业务方这个结论只能当作有条件的参考不能当作决策依据。2.3 入门需要的前置知识盘点因果模型不是一门需要极深数学才能入门的学科但它确实有几个前置门槛。概率论方面你需要熟悉条件概率、期望、方差、独立性、条件独立性这些概念特别是条件独立性和 d-分离的思想是读图的钥匙。统计学方面回归、假设检验、置信区间、聚类稳健标准误是基础倾向得分、匹配、加权这些技术也要能看懂。机器学习方面你需要理解过拟合、交叉拟合cross-fitting、正则化因为在做 CATE 估计时元学习器大量依赖这些机制来控制过拟合带来的偏差。因果图是独立的语言需要单独花时间学。建议先把 d-分离、后门准则、前门准则、碰撞点collider这四个概念彻底吃透。其中碰撞点是最反直觉的两个原本独立的变量如果同时作为某个变量的原因那么在这第三个变量上做条件反而会让它们产生关联。这就是著名的对撞偏差也叫 Berkson 悖论。很多人做特征筛选时无脑控制所有变量结果正好把对撞点控制了凭空造出相关性。提示判断一个变量该不该进模型先问它在图上处于什么位置而不是先问它的统计显著性。3. 把骨架拆开DAG、do算子与反事实3.1 用一张图讲清结构因果模型结构因果模型由三部分组成一组变量、一组结构方程、一组外生噪声。每个变量都由它的父节点决定形式化写作 $X_i f_i(PA_i, U_i)$其中 $PA_i$ 是父节点集合$U_i$ 是外生噪声。这个式子看起来平淡但它带来一个非常强的能力你可以对模型做干预。所谓干预就是把某个变量的生成机制从 $f_i$ 替换成一个常数这个操作在图上表现为断开该节点所有入边。这就是 do 算子和普通条件概率的分水岭。理解 do(Xx) 和 P(Y|Xx) 的区别是入门因果模型最重要的一步。P(Y|Xx) 是在观测到 Xx 的人群里Y 的分布这个人群里可能混着大量因为共同原因而选择了 Xx 的人。而 P(Y|do(Xx)) 是如果我们强制把 X 设成 xY 的分布会怎样这是一个干预分布对应随机实验的结果。两者只有在 X 与 Y 之间没有后门路径时才相等这个条件就是后门准则的核心。有向无环图DAG是把结构方程可视化的工具。三种基本结构要记住链式 X → Z → YZ 是中介控制它会阻断因果通路分叉 X ← Z → YZ 是混杂控制它会阻断后门路径对撞 X → Z ← YZ 是碰撞点控制它反而会打开一条原本关闭的路径。几乎所有因果图的分析都是这三种结构的组合判断。3.2 后门准则、前门准则与调整集的构造后门准则的表述是如果一组变量 Z 满足1Z 阻断了 X 到 Y 的所有后门路径2Z 中不含 X 的后代那么 P(Y|do(Xx)) 可以通过对 Z 做调整得到$$P(Y|do(Xx)) \sum_z P(Y|Xx, Zz) P(Zz)$$这个公式是几乎所有后门调整方法回归、分层、匹配、IPW、双重稳健估计的共同源头区别只在于用什么模型估计 $P(Y|X,Z)$ 和 $P(Z)$。回归本质上是把求和换成了线性模型的积分IPW 是把 $P(Z)$ 换成了逆概率权重双重稳健估计则同时建模两者只要其中一个模型对结果就一致。前门准则适用于混杂因子不可观测但存在一个完全中介的情形。比如 X → M → Y同时存在一个未观测的 U 同时影响 X 和 Y。此时后门调整失效但可以通过两段回归把效应拼起来先估计 X 对 M 的效应再估计 M 对 Y 的效应此时 X 作为控制变量满足后门准则两者相乘。这个技巧在医疗、营销归因里非常有用因为它允许一部分混杂不可观测。调整集的选择有两个常见误区。第一是控制得越多越好这会导致对撞偏差和控制中介把真实效应部分或全部抵消。第二是控制所有可观测变量这在时间维度上尤其危险因为你可能控制了处理发生之后才出现的变量这些变量本身就是结果的一部分。我的一般原则是只控制处理发生之前、且在因果图上被识别为混杂的变量。3.3 潜在结果框架与四个必须写进报告的假设潜在结果框架把因果效应定义为同一单元在两个处理状态下的结果之差。对单元 i记 $Y_i(1)$ 和 $Y_i(0)$ 分别是接受处理和未接受处理时的潜在结果个体处理效应是 $Y_i(1) - Y_i(0)$。问题是这两个值永远只能观测到一个另一个是反事实。因果推断的全部技术难点都源于这个缺失数据问题。要让估计量有意义必须引入四个假设我强烈建议把它们写进每一份因果分析报告SUTVA个体处理稳定性一个个体的结果不依赖于其他人的处理分配且处理只有一种版本。社交网络、双边市场里这条经常被违反。可忽略性无未观测混杂给定协变量后处理分配与潜在结果独立。这是最核心、也最难验证的一条。正性重叠任何协变量取值下接受处理的概率都严格大于 0 且小于 1。实践中表现为某些人群完全没有对照样本。一致性观测到的结果等于对应处理状态下的潜在结果。这四条里可忽略性是唯一无法用数据检验的只能靠领域知识和敏感性分析来论证。我通常的做法是把可能的未观测混杂列出来逐一评估它与处理、结果的关联强度再用 E-value 之类的工具算一下要推翻结论需要多强的未观测混杂这个数字比任何 p 值都更能说服业务方。4. 动手实操从画图到跑出可反驳的因果效应4.1 环境准备与依赖清单先给出我常用的环境配置。这套组合在最近两年的项目里比较稳定Python 3.9 到 3.11 都能跑。pip install dowhy0.11.1 \ econml0.15.0 \ pandas2.1.4 \ numpy1.26.4 \ scikit-learn1.4.0 \ networkx3.2.1 \ matplotlib3.8.2DoWhy 负责识别、估计、反驳三段式流程EconML 负责异质性效应和与机器学习模型的结合networkx 用来画 DAG。版本上建议锁死DoWhy 在 0.9 到 0.11 之间 API 变动不小老教程里的identify_effect(proceed_when_unidentifiableTrue)这类写法在新版本里行为已经不同。注意不要在同一环境下混装多个因果库的旧版本CausalML、EconML、DoWhy 对 scikit-learn 版本的要求经常冲突用 conda 单独建环境最省事。数据准备上我建议先用半合成数据验证流程。EconML 自带了一些模拟数据生成器但更贴近真实场景的做法是从自己的业务数据里抽一部分真实的协变量分布然后按一个已知的结构方程人工造出处理变量和结果变量。这样你既知道真实效应是多少又保留了真实数据的复杂结构是检验整条流水线最扎实的方式。4.2 第一步永远是先画图再写代码我见过太多人跳过画图直接跑模型最后拿到的结论自己都解释不清楚。画 DAG 的过程本质上是把业务假设显式化的过程。这里用 networkx 画一个典型的营销场景折扣力度discount影响购买purchase用户历史消费history和渠道来源channel同时影响折扣发放和购买。import networkx as nx import matplotlib.pyplot as plt g nx.DiGraph() g.add_edges_from([ (history, discount), (history, purchase), (channel, discount), (channel, purchase), (discount, purchase), (season, history), (season, channel), ]) # 找出所有混杂同时是 discount 的祖先、也是 purchase 的祖先 def ancestors(g, node): return nx.ancestors(g, node) confounders ancestors(g, discount) ancestors(g, purchase) print(需要控制的混杂集合:, confounders)这段代码会输出 history、channel、season 三个变量。手工画图时容易漏掉 season 这种上游的季节变量但它一旦同时影响渠道和历史消费就是一个不可忽略的混杂。这个自动求祖先交集的方法虽然简单却能覆盖大部分日常场景比凭感觉列变量靠谱得多。画完图之后要做的第二件事是列出所有你控制不了的变量。上例中如果有平台算法推荐位这种同时影响折扣发放和购买、又完全没记录在数据里的变量就必须在报告里明确写出来并做敏感性分析。承认不确定性比假装确定更专业。4.3 用 DoWhy 跑通 ATE 估计与反驳检验下面是一个可以端到端跑通的例子结构是识别、估计、反驳三步。import numpy as np import pandas as pd from dowhy import CausalModel np.random.seed(42) n 5000 history np.random.normal(50, 15, n) channel np.random.binomial(1, 0.4, n) season np.random.normal(0, 1, n) # 处理变量折扣力度受混杂影响 discount 5 0.06 * history 2.5 * channel 1.2 * season np.random.normal(0, 3, n) discount np.clip(discount, 0, 30) # 结果变量购买金额真实因果效应为 1.8 purchase 200 1.8 * discount 0.7 * history 15 * channel 8 * season np.random.normal(0, 20, n) df pd.DataFrame({ history: history, channel: channel, season: season, discount: discount, purchase: purchase }) model CausalModel( datadf, treatmentdiscount, outcomepurchase, common_causes[history, channel, season] ) identified model.identify_effect(proceed_when_unidentifiableFalse) estimate model.estimate_effect( identified, method_namebackdoor.linear_regression, target_unitsate ) print(ATE 估计值:, estimate.value) refutation model.refute_estimate( identified, estimate, method_namerandom_common_cause, num_simulations100 ) print(refutation)真实效应是 1.8跑出来的估计值一般会落在 1.7 到 1.9 之间。如果明显偏离先检查混杂列表是否漏了变量再检查函数形式是否被误设。线性回归估计后门调整在经济含义清晰、样本量大的场景下表现不错但一旦真实关系是非线性的就会被系统性带偏。这时候要换双重稳健估计DoWhy 支持backdoor.econml.dml.DML之类的接口。反驳检验这一步绝对不能省。DoWhy 提供的反驳手段包括随机共同原因、安慰剂处理、数据子集、增加未观测混杂等。我尤其推荐两个安慰剂处理和增加未观测混杂。安慰剂处理是把处理变量替换成一个随机变量如果还能跑出显著效应说明你的流程本身有泄漏。增加未观测混杂则是人为注入一个混杂观察估计值偏移的敏感度这直接对应上面说的 E-value 思路。4.4 异质性效应用 EconML 找出对谁最有效业务方真正关心的往往不是整体有没有效果而是对哪部分人效果最好。这时候需要估计 CATE条件平均处理效应。EconML 的CausalForestDML是我用下来比较稳的选择它结合了双重机器学习去偏和因果森林的非参数异质性建模能力。from econml.dml import CausalForestDML from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier Y df[purchase].values T df[discount].values X df[[history]].values # 想刻画异质性的维度 W df[[channel, season]].values # 控制变量 est CausalForestDML( model_yGradientBoostingRegressor(max_depth4, n_estimators200), model_tGradientBoostingRegressor(max_depth4, n_estimators200), n_estimators500, min_samples_leaf50, discrete_treatmentFalse, cv5, random_state42 ) est.fit(Y, T, XX, WW) cate est.effect(X) print(CATE 均值:, cate.mean()) print(CATE 分位数:, np.percentile(cate, [10, 50, 90]))这里有几个参数值得展开说。min_samples_leaf50不是随便设的它是控制异质性粒度的关键太小会导致局部估计噪声巨大太大会把异质性抹平。我的经验值是在样本量的千分之一到百分之一之间选然后看 CATE 分位数的稳定性。cv5用的是交叉拟合目的是消除过拟合带来的正则化偏差这是双重机器学习能保持渐近正态性的前提一定要开。model_t用回归器还是分类器取决于处理变量的类型。连续处理如折扣力度、价格用回归器二值处理发券/不发券要用GradientBoostingClassifier否则模型对倾向得分的拟合会有偏。这个细节很多教程会忽略但在二值处理场景下影响很大。4.5 因果感知模型融合把因果层接进预测模型因果感知模型融合这个说法最近出现频率很高它指的是把因果结构或因果效应估计作为一层与常规的预测模型融合起来。核心动机很实在纯预测模型学的是 P(Y|X)它会优先抓住任何能降低损失的关联包括那些不稳定、不可干预的伪相关。一旦环境变化渠道结构调整、大促节奏改变、用户群体迁移这些伪相关的方向就变了模型表现会断崖式下跌。融合的思路大致有三种。第一种是两阶段拼接先用因果模型算出每个样本的 CATE再把这个 CATE 作为特征喂给下游模型。这种做法实现简单适合快速验证。第二种是残差建模把结果拆成因果可解释部分 环境相关残差部分分别建模。第三种是表征层面的因果约束在训练损失里加入惩罚项让模型学习到的表征在不同环境下保持不变也就是常说的不变风险最小化思路。# 两阶段拼接的极简示例 from sklearn.linear_model import Ridge from sklearn.model_selection import train_test_split # 用上一步的因果模型估计 CATE作为新特征 df[cate] est.effect(df[[history]].values) # 下游模型预测未来购买使用 CATE 而非原始折扣 X_down df[[history, channel, season, cate]] y_down df[purchase] X_tr, X_te, y_tr, y_te train_test_split(X_down, y_down, test_size0.3, random_state42) down_model Ridge(alpha1.0).fit(X_tr, y_tr) print(下游模型 R2:, down_model.score(X_te, y_te))这个例子里把原始discount换成cate的价值在于CATE 表达的是这个样本对干预的敏感度它是一个更稳定的、跨环境可迁移的量。在真实的推荐或营销系统里这种做法能显著降低模型在新渠道、新人群上的波动。当然代价是要先投入资源做因果估计而且因果估计本身的假设如果不成立融合反而会引入新的偏差。我的建议是先从两阶段拼接开始验证收益明显后再考虑表征层面的深度耦合。5. 识别假设不成立时数据会怎么报警5.1 五个高频异常现象与背后的原因现象一安慰剂处理也显著。这几乎总是意味着流程里存在信息泄漏比如处理变量里混入了结果变量的未来信息或者特征工程时不小心用了全量数据做标准化。排查方法很简单严格按时间切分所有统计量只用训练期数据计算。现象二加了控制变量后效应符号翻转。这通常是对撞偏差的典型信号。你控制的某个变量可能是处理的下游结果控制它反而打开了后门路径。回到 DAG 重新判断这个变量的位置尤其是那些在处理之后测量的变量。现象三正性被严重违反权重出现极端值。IPW 类方法的权重分布一旦出现很大的尾部估计量方差会爆炸。诊断方式是画倾向得分的重叠图看处理组和对照组的分位数范围。如果重叠区域太小只能通过截断权重或改用匹配方法并明确说明外推范围受限。现象四随机种子一换结论就变。说明样本量对当前异质性粒度来说不够或者模型复杂度过高。先降复杂度再考虑合并某些协变量维度。现象五不同估计方法给出差距很大的结果。线性回归、IPW、双重稳健估计的结论差异大往往说明函数形式误设严重。这时候优先相信双重稳健估计同时做交叉验证式的诊断把数据分半一半估计倾向得分一半估计结果模型看两个子模型各自的预测表现。5.2 问题排查速查表症状可能原因排查动作处理方式安慰剂处理显著信息泄漏检查特征是否用到未来信息严格时间切分重建特征效应符号翻转对撞偏差重新审视图上变量位置移除处理后的变量权重极端正性违反画倾向得分重叠图截断权重或改匹配结果不稳定样本不足或过拟合换种子重复估计降低模型复杂度方法间差异大函数形式误设对比多个估计器采用双重稳健估计置信区间过宽有效样本量低检查重叠与权重分布合并稀疏协变量分层这张表是我自己项目里攒下来的不是教科书顺序。实际排查时建议按先查泄漏、再查图、最后查模型的顺序因为前两类问题用模型调参是解决不了的越调越偏。5.3 几条不写在文档里的实操心得把假设写进 PPT 第一页。我现在的习惯是任何因果分析汇报第一页就写清楚四条识别假设和它们各自的合理性依据。这么做的直接好处是业务方会主动告诉你这个假设在我们场景下不成立这些问题如果等到结论出来再被质疑返工成本极高。优先做实验因果模型当补充。能随机分流的场景就随机分流因果模型的强项是在不能实验时给出有条件的答案以及实验后回答为什么和对谁。敏感性分析比点估计重要。与其纠结 ATE 是 1.7 还是 1.9不如花时间算清楚要推翻这个结论需要多强的未观测混杂。前者对决策影响有限后者直接决定结论能不能用。别忽视中介分析。很多时候业务方问的是为什么有效而不是有没有效。中介分析能告诉你效应通过什么路径传导这对后续优化策略的价值往往更大。因果图要迭代。第一版图一定有错随着对业务的了解加深图会不断修正。我一般每季度重新过一遍核心项目的 DAG经常能发现之前漏掉的关键混杂。6. 哪些场景值得投入因果模型代价又是什么6.1 六类典型落地的场景定价与促销这是因果模型最经典的应用场。折扣力度、优惠券面额、会员价格对购买的影响天然存在大量混杂高价值用户更容易拿到大额券也天然适合做异质性分析找出对不同用户的最优力度。用 CATE 做差异化定价在很多零售场景里能带来实打实的利润提升。推荐与内容分发推荐系统最大的问题是反馈环。用因果模型做去偏可以让模型学到用户真正因为这条内容而产生了偏好而不是用户因为被推荐了所以才点。这在冷启动和长期留存优化上价值明显。用户增长与留存各类干预手段推送、弹窗、活动的净效应评估。这里需要特别注意 SUTVA 的违反因为推送存在用户之间的社交影响一个人收到推送可能影响他的好友。风控与信用策略调整对逾期率、通过率的影响评估。这类场景通常不能做随机实验成本太高且涉及合规准实验方法如断点回归用得很多。医疗与健康分析治疗效果评估、副作用归因。这是因果推断的历史发源地假设要求最严格对未观测混杂的敏感性分析要求最高。产品与运营决策功能上线、界面改版、流程优化。这类场景的困难在于效果往往很小而噪声很大需要足够的样本量和精细的方差控制。这六类场景有一个共同点决策具有干预性且干预不能随便做随机实验或者实验成本很高。如果一个问题只是纯预测比如预测明天销量用于补货因果模型不一定比常规机器学习更有优势。6.2 能力边界与投入代价评估因果模型不是万能的它的边界非常清晰。第一它无法给你数据里不存在的信息。如果关键混杂完全没被记录任何后门调整都救不了你只能靠敏感性分析量化风险。第二它对图错误零容忍。图是因果结论的地基画错了后面全错而且错误往往是隐性的不会报错。第三它不能替代领域知识。所有识别策略的合法性判断最终都要回到这个业务机制合不合理上。投入代价上我的经验是单个中等复杂度的因果分析项目数据准备和图画阶段大概占总工时的 50%估计只占 20%剩下 30% 花在反驳检验和敏感性分析上。很多人把时间分配反了在估计方法上反复折腾却对图和数据质量敷衍了事结果就是结论经不起推敲。工具链的成熟度这两年提升很快。DoWhy 把识别、估计、反驳标准化了EconML 把异质性估计和机器学习结合得比较顺画图和诊断也都有现成库。真正的门槛不在工具而在把业务问题翻译成正确的因果问题以及诚实面对假设不成立的风险。我个人在实际项目里的体会是因果模型最大的价值往往不是那个点估计数字而是它逼着团队把我们到底假设了什么这件事想清楚。这个思考过程本身通常就能避免好几次拍脑袋决策。
返回列表