把相关换到因果时踩过的坑

从纯相关性模型到因果推断的实践过程,包括为什么必须做、怎么在实际数据上实现、以及在尝试过程中踩过的坑。去年做一个产品优化项目时,我们遇到了一个典型的相关性误导问题。

背景与动机

去年做一个产品优化项目时,我们遇到了一个典型的相关性误导问题。用户行为数据表明,使用高级功能的用户留存率明显更高。团队最初的建议很直接:更多引导用户使用高级功能,就能提升留存。

但仔细一想,这个逻辑有问题。用户愿意用高级功能,可能本来就是产品忠诚度较高的群体,而不是高级功能本身导致了更高留存。这种情况下,强推高级功能可能不仅无效,还可能让普通用户觉得麻烦反而流失。

这不是个例。在实际业务中,我们经常面对类似的问题:

  • 营销活动参与度和收入增长正相关,但活动是否真的带来了新增收入?
  • 功能使用频率和满意度正相关,但高频使用是因为满意度高还是反过来?
  • 用户画像特征和转化率相关,但改变这些特征真的能提升转化?

相关性只能告诉我们"什么和什么一起出现",但决策需要的是"改变什么会导致什么变化"。这就是因果推断的价值所在。

实现路径

第一步:因果图构建

因果推断的第一步是建立因果图,把变量之间的因果假设用有向无环图(DAG)表示出来。这比想象的要难,因为数据本身不会告诉我们因果方向,需要结合领域知识来设定。

在我们的用户留存案例中,初始的因果假设可能长这样:

graph LR A[用户特征] --> B[功能使用] A --> C[留存结果] B --> C D[外部因素] --> C

这个图表达了几个假设:用户特征既影响功能使用,也直接影响留存;功能使用影响留存;外部因素(如竞品活动、季节性)也影响留存。

第二步:因果发现算法

完全靠领域知识构建因果图在很多场景下不现实,特别是变量较多或者领域知识不完善时。这时可以尝试因果发现算法,从数据中自动学习因果结构。

我试了几种常用的算法:

PC 算法(Peter-Clark)

  • 基于条件独立性测试的经典方法
  • 对中小规模变量表现不错
  • 但对条件独立性测试的样本量要求较高
  • Python 实现:使用 causal-learn
from causallearn.search.ConstraintBased.PC import pc
from causallearn.utils.GraphUtils import GraphUtils

# 假设 data 是 pandas DataFrame
cg = pc(data, alpha=0.05)  # alpha 是显著性水平
dag = cg.G.graph  # 得到因果图

# 可视化
pyd = GraphUtils.to_pydot(cg.G, labels=data.columns)
pyd.write_png('pc_causal_graph.png')

GES 算法(Greedy Equivalence Search)

  • 基于评分函数的搜索方法
  • 效率通常比 PC 算法高
  • 对数据噪声相对鲁棒
  • 需要选择合适的评分函数(BIC、BDeu 等)

NOTEARS 算法

  • 基于连续优化的方法
  • 适合大规模变量
  • 但假设是线性高斯模型,限制了应用场景

实际使用时,我发现这些算法都有各自的局限。PC 算法对样本量敏感,GES 算法的搜索策略可能陷入局部最优,NOTEARS 的模型假设又过于严格。而且,即使算法输出了因果结构,也需要领域专家的验证和调整。

第三步:因果效应量化

因果图建好后,就需要量化因果效应。我们关心的是干预一个变量对另一个变量的实际影响。

倾向得分匹配(PSM)

  • 用在观察性数据中模拟随机实验
  • 通过匹配相似样本减少选择偏差
  • 对二元干预变量效果较好
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import NearestNeighbors
import numpy as np

# 计算倾向得分
propensity_model = LogisticRegression()
propensity_model.fit(covariates, treatment)  # treatment 是 0/1 二元变量
propensity_scores = propensity_model.predict_proba(covariates)[:, 1]

# 匹配处理组和对照组
treated_indices = np.where(treatment == 1)[0]
control_indices = np.where(treatment == 0)[0]

treated_scores = propensity_scores[treated_indices]
control_scores = propensity_scores[control_indices]

nbrs = NearestNeighbors(n_neighbors=1).fit(control_scores.reshape(-1, 1))
distances, indices = nbrs.kneighbors(treated_scores.reshape(-1, 1))

matched_control = control_indices[indices.flatten()]

# 计算平均处理效应(ATE)
ate = np.mean(outcome[treated_indices]) - np.mean(outcome[matched_control])

双重机器学习(DML)

  • 结合机器学习模型处理高维协变量
  • 对干预变量和结果分别建模
  • 使用交叉拟合减少过拟合偏差
from econml.dml import CausalForestDML
from sklearn.ensemble import GradientBoostingRegressor

# 使用因果森林进行双重机器学习
causal_forest = CausalForestDML(
    model_y=GradientBoostingRegressor(),  # 结果模型
    model_t=LogisticRegression(),  # 干预模型
    n_estimators=100,
    min_samples_leaf=5
)

causal_forest.fit(Y=outcome, T=treatment, X=covariates)
treatment_effect = causal_forest.effect(X=covariates)  # 得到个体处理效应

工具变量(IV)

  • 处理存在未观测混淆变量的情况
  • 需要找到与干预相关但与结果无关的工具变量
  • 现实中很难找到合适的工具变量

踩坑与反思

样本量陷阱

最初我以为几千条样本就足够做因果发现了,但实际运行算法时才发现,条件独立性测试对样本量要求远超预期。变量越多,需要的样本量呈指数级增长。

在只有万级样本但有几十个变量的情况下,PC 算法经常输出一些可疑的因果结构,或者干脆无法确定某些边的方向。这提醒我,因果发现不是魔法,它依然受数据量限制。

混淆变量遗漏

一个真实的教训:在一次营销活动效果评估中,我们遗漏了"用户生命周期阶段"这个重要混淆变量。结果显示营销活动对转化有正向影响,但加上生命周期阶段后,效果就不显著了。

混淆变量是因果推断的敌人,但更可怕的是你不知道自己遗漏了哪些。经验和领域知识在这里比算法更重要。

非线性关系误判

早期的尝试中,我假设所有关系都是线性的,直接用了基于高斯假设的算法。但实际业务数据中,很多关系是非线性的,甚至存在阈值效应。比如营销投入在一定范围内有正面效果,超过某个阈值反而负面。

后来改用了更灵活的模型:

  • 用梯度提升树替代线性回归建模结果变量
  • 引入样条函数处理非线性关系
  • 分段建模处理阈值效应

因果图的脆弱性

还有一个容易被忽视的问题:因果图对假设非常敏感。稍微改变几个边的方向,因果效应的估计结果可能完全不同。

这意味着我们不能只相信算法输出的一个"最优"因果图,而应该:

  • 生成多个合理的因果图结构
  • 比较不同假设下的因果效应
  • 对结果做敏感性分析

结果与边界

经过这些折腾,最终我们在用户留存项目中得到了一个更清晰的结论:高级功能使用和留存确实存在因果关系,但效应大小远低于相关性的暗示。更重要的是,因果分析告诉我们,对不同用户群体,高级功能的效果差异很大。

这个发现改变了产品策略:从"统一推高级功能"变成"针对特定用户群体精准推荐",最终的留存提升效果比之前预期的更务实、更可持续。

但因果推断也不是万能药。它在这些问题上依然面临限制:

  • 完全随机化实验仍然是因果推断的金标准,但在很多业务场景下成本太高或不道德
  • 观察性数据的因果推断总是有假设条件,这些假设本身难以验证
  • 复杂系统的因果链条很长,我们通常只能关注局部因果效应
  • 因果推断不解决反事实的全部问题,特别是极端干预的长期影响

结语

从相关性到因果性,这不仅是统计方法的升级,更是思维方式的转变。相关性告诉我们"什么可能有用",因果性告诉我们"什么真的有用"。

在实践中,因果推断更像是一种谨慎的思维方式,而不是一套固定的算法流程。它要求我们不断质疑假设、验证边界、承认不确定性。这种谨慎在数据驱动的时代反而更有价值。

做完这些工作,我最大的收获不是学会了几个算法,而是对"相关"和"因果"这两个词有了更深的敬畏。模型可以快速给出预测,但决策的智慧往往藏在因果关系的细节里。


参考

版权声明: 本文首发于 指尖魔法屋-把相关换到因果时踩过的坑https://blog.thinkmoon.cn/post/331-ai-causal-inference-correlation-causality/) 转载或引用必须申明原指尖魔法屋来源及源地址!