1. 从“相关不等于因果”到线性非高斯无环模型
做数据分析的朋友应该都有过这种经历:手握一堆观测数据,相关矩阵跑熟了,回归也拟合了,但别人一问“到底是A导致了B,还是B导致了A”,你瞬间哑火。传统回归模型只能告诉你关联强度和方向系数,根本无法回答因果方向。这正是因果推断领域最让人头疼的地方。
我最初接触线性非高斯无环模型(LiNGAM)是在处理一组用户行为日志时。当时我在分析“页面浏览时长”“用户满意度评分”“跳出率”三组指标之间的因果关系,结果普通的相关分析、回归分析全做完了,还是分不清因果链条到底是怎样的。后来用了非高斯假设的思路,才把方向确定下来。这篇文章就把我实际操作中总结出来的经验完整拆解一遍,尽量让刚接触因果推断的读者也能照着上手。
LiNGAM的全称是 Linear Non-Gaussian Acyclic Model,核心解决的是“仅凭观测数据,如何唯一确定因果方向”的问题。它的适用场景非常明确:变量之间是线性关系、噪声是非高斯分布、底层因果结构是无环图。凡符合这三条的数据,理论上都能用这套框架找出因果顺序和路径系数。
这篇文章适合三类读者:一是做数据分析但被因果方向困扰的从业者;二是做机器学习特征选择时被共线性坑过的人;三是对结构方程模型有了解但想知道“非高斯性”到底能带来什么突破的研究者。我会从原理讲起,逐步过渡到实操,最后把我在真实项目中踩过的坑全部列出来。
2. 为什么非得“非高斯”不可:可识别性问题的根源
其实因果推断领域有个让很多人困惑的起点:为什么常规线性模型无法确定因果方向?这要从误差项的分布说起。
2.1 高斯假设下的对称困境
假设有两个变量X和Y,真实的因果结构是X导致Y,线性关系可以写为:
Y = βX + E,E ⊥ X
如果E服从高斯分布,那么反过来看,我们完全可以把模型写成:
X = (1/β)Y + E'
这个反向模型的误差项E'同样服从高斯分布,且与Y相互独立。数学上,两个方向的模型在统计性质上完全对称,似然值相同。也就是说,在纯高斯噪声的线性框架下,数学理论告诉我们无法区分“X→Y”还是“Y→X”——这就是结构方程模型中的不可识别问题。
这个问题卡了统计学家很多年。传统做法要么靠随机实验来打破对称性,要么靠领域知识去猜。但现实里,很多场景根本不允许做实验,面试时会被追问的“你到底凭什么说这个变量导致那个变量”就卡在这里。
2.2 非高斯分布如何打破对称
2006年左右,有几位学者的工作彻底改变了这个困境。他们证明了一个关键结论:如果噪声项服从非高斯分布,比如均匀分布、指数分布、对数正态分布,或者任何非零峭度的分布,那么因果方向就不再对称了。
从原理上讲,非高斯性让数据携带了“方向信息”。以X和Y满足真实模型Y = X + E为例,如果E服从均匀分布U(0,1),X服从U(0,1),那么变量Y的分布是三角形状的,向右偏斜。如果我们假设错误方向Y→X,回归残差在统计上会表现出与Y的依赖关系。独立性的差异,就是方向识别的依据。
一个更直观的理解方式是“独立成分分析”的视角:当噪声非高斯时,混合信号中独立成分的分离结果是唯一的,而这种唯一性正好对应因果顺序的唯一性。这和鸡尾酒会上分离不同说话人声音的原理是一致的——音频信号天然非高斯,所以独立成分分析才能被发明出来。
2.3 LiNGAM的三大前提条件
把LiNGAM用在实际数据上,得先过一遍它的三条标准假设,缺了哪条结果都不作数。
第一条是线性关系。变量之间必须是线性函数关系,非线性数据需要先用其他方法处理或者改造。尽管后续也有非线性扩展版本,但经典LiNGAM只处理线性情形。
第二条是无环结构。底层因果图不能存在环,比如“A→B→C→A”这种结构直接出局。无环性保证了因果顺序的良定义性。实际业务数据中,反馈回路几乎是常态,这一点需要特别警惕。
第三条是非高斯连续噪声。误差项必须服从非高斯分布且相互独立,同时不能有未观测的混杂因素。最后这条最苛刻,隐藏的混杂变量会直接破坏结论的可靠性。
3. 线性非高斯无环模型的核心原理
明确了前提条件,接下来就可以拆模型本身了。这个模型看起来就是一串线性方程,但它对“如何确定因果顺序”有一套非常精妙的设计。
3.1 模型的数学表达
LiNGAM的数学形式是:
xi = Σ b_ij * xj + ei,其中求和覆盖所有“在因果顺序上排在xi前面的变量”
这里的b_ij是路径系数,表示变量xj对xi的直接影响强度。e_i是噪声项,服从非高斯分布,且所有e_i相互独立。每一条方程代表一个变量如何由其父变量和噪声生成。
这里需要特别提醒一个容易混淆的点:因果顺序不一定等于变量名的顺序。比如我们收集了X、Y、Z三个变量,真实的因果顺序可能是Z→X→Y,那么Y的方程里就同时包含X和Z,而X的方程里只有Z,Z的方程里前面没有任何变量,即Z是外生变量。
外生变量是找因果顺序的切入点。整个模型的求解过程,本质上就是不断找外生变量、剥离影响、再找下一个外生变量的迭代过程。
3.2 可识别性定理告诉我们的真相
LiNGAM有个核心定理:在上述三条假设成立的前提下,只要数据量足够,贝叶斯网络的结构和参数可以被唯一识别。这等于宣告:非高斯性把我们从“只能识别到马尔可夫等价类”的困境中解救了出来。
对比一下就清楚了。传统基于高斯假设的因果发现方法,比如PC算法,只能把候选模型压缩到马尔可夫等价类,最后通常要输出一堆“可能的方向”,无法给出唯一答案。而LiNGAM直接输出唯一的DAG结构和因果系数,这在实际业务使用中简直是降维打击。
但这里有个微妙点必须讲清楚:唯一定理只是在理论层面保证。实际数据中样本量有限、非高斯性可能不够强、独立检验存在误判,都可能导致算法输出错误方向,这也是后文要谈实操注意点的原因。
3.3 因果强度与因果顺序的关系
模型输出的结果分为两层,很多人只盯着系数,却忽略了顺序层的信息。
因果顺序告诉我们变量之间的层级关系,比如找到结果是“Z最先出现,然后X产生,Y最后产生”。这个顺序直接对应了DAG的拓扑序,所有箭头只能从靠前的变量指向靠后的变量。路径系数则告诉我们影响的强弱,比如Y = 0.8X + 2.5Z + e,0.8和2.5就是直接效应。
我自己使用的心得是:顺序信息和系数信息要结合着看。有些场景下即使系数很小,只要顺序关系稳定可靠,也说明存在因果影响;反过来,如果一个路径系数很大但方向判定错误,那整条结论就全错了。因果方向永远是第一位的,系数量级排第二。
4. 实际操作:从数据到因果图全流程
理论说得再漂亮,落地才是硬道理。我把自己在真实项目里的操作流程整理成一个五步法,每一步都标注了容易出错的地方。
4.1 第一步:数据预处理是做还是不做
LiNGAM对数据质量非常敏感,预处理直接影响最终结果的可靠性。
首先是规范化问题。很多人习惯先做标准化再跑模型,这个操作在LiNGAM下问题很大,因为标准化本质上是一种线性变换,它会改变噪声项的分布形态。如果源数据的噪声是非高斯的,经过标准化后非高斯特征可能被稀释甚至消失,导致模型精度下降。我在项目中通常只用原始数据或仅做中心化处理,中心化不影响噪声分布的非高斯形态。
其次是处理缺失值。LiNGAM要求完整数据集,缺失值需要插补。但插补本身会引入人为噪声,我建议优先做行删除,只有在删除后样本量太小时才考虑用多重插补。
还有一个常被忽视的步骤是异常值检查。LiNGAM对异常值极其敏感,一个离群点就可能让独立性检验完全失效。我在每次跑模型前都会画箱线图检查异常值,轻度的做截尾处理,严重的直接剔除。
4.2 第二步:非高斯性检验
数据到底够不够“非高斯”,决定了LiNGAM能不能发挥最强威力。
我常用的做法是计算每个变量的偏度和峰度。偏度绝对值大于0.5或者峰度偏离3较多的,通常都算有不错的非高斯性。另外可以跑一下Jarque-Bera检验,p值小于0.05说明拒绝正态性假设,模型有效性更有保障。
这里有个实操上的小心得:非高斯性不一定要特别强,只要不勉强算作高斯就能用。但如果数据本身就接近正态分布,坦白说,LiNGAM的优势就会弱化,结果可能会不稳定。我的建议是,在跑模型之前先对每个变量做Q-Q图目检,能直观看到非高斯成色。
4.3 第三步:跑通DirectLiNGAM算法
市面上已经有很多LiNGAM的开源实现。我在Python里最常用的是lingam库,它实现了几种变体算法,其中DirectLiNGAM是当前最推荐的一种。
DirectLiNGAM的基本思想很优雅:不需要做独立的成分分析,而是通过反复执行“找外生变量+回归剔除影响”两步来完成因果顺序的求解。
具体来说是:先通过非高斯性确定哪个变量最可能是外生变量,也就是因果顺序第一位的变量,标准是它与其他变量的相关性最弱;然后把这个外生变量对剩余变量的影响用回归的方式剔除掉,得到残差;接着在残差空间上重复上述步骤,直到所有变量的因果顺序都被确定。
举个我在某跨平台业务数据上跑过的例子。三个核心指标是“用户停留时长D”“内容点赞数L”“转化率C”,原始数据看起来彼此都相关。用lingam库跑出因果顺序后,结果是D→L→C,也就是说停留时长因果性地影响点赞行为,点赞行为又因果性地影响转化率。这个结论让业务团队非常兴奋,因为传统的相关分析只能告诉他们“这三者强相关”,而LiNGAM直接给出了全链路的因果方向。
实际上跑代码的步骤非常简单。假设我已经把数据整理进DataFrame变量df中,然后:
import lingam import pandas as pd # df已经是预处理好的数据,每列一个变量 model = lingam.DirectLiNGAM() model.fit(df) # 查看因果顺序 print(model.causal_order_) # 查看因果效应矩阵 print(model.adjacency_matrix_)其中causal_order_返回的是变量索引的列表,比如[2, 0, 1]表示索引为2的变量最先出现。adjacency_matrix_是邻接矩阵,第i行第j列的元素代表从变量i指向变量j的因果效应系数。
我第一次跑通时正好怀疑数据处理有问题,所以在语料里把同样的逻辑套到模拟数据上验证了一遍,确认模型确实能恢复预设的因果结构,然后才用到真实数据上。这其实是我建议每个用LiNGAM的人都做的一步:先从已知因果结构的仿真数据上确认算法实现没问题,再转向真实业务数据。
4.4 第四步:解读因果图的输出
拿到causal_order_和adjacency_matrix_后,解读阶段也算技术活。
因果顺序的意义比较直接,它告诉你一个变量链条。而邻接矩阵解读有几个注意点。矩阵中某个元素值为0,代表该路径不存在。如果元素值接近0但并非0,需要结合统计学意义判断是弱因果还是噪声导致的假象,这时通常建议看p值或者用bootstrap方法获取置信区间。
还有一点必须提醒:因果效应系数和回归系数不是一回事。普通回归系数是“控制了其他变量后”的条件关联,而LiNGAM输出的路径系数是结构方程中的直接因果效应。如果模型里存在中介路径,因果效应系数可能看起来很小,但间接效应加总后总效应很大。比如品牌曝光A通过用户信任M影响最终购买B,直接路径A→B的系数可能只有0.2,但间接路径A→M→B加总后的总效应可能高达0.8。解读时得同时看直接和间接两条路径。
4.5 第五步:验证稳健性和替代模型对比
模型输出的结果不能直接拿去汇报,稳健性验证这关必须过。
我习惯用两种方式验证。第一种是bootstrap重采样,对原始数据有放回地抽样比如1000次,每次都跑一遍LiNGAM,看因果方向和系数在不同样本中的稳定性。如果1000次中有900次以上都得到一致的因果顺序,这个结论就比较扎实了。
第二种是和替代建模思路对比。如果数据还适合跑其他因果发现算法,比如基于条件独立性检验的PC算法,我会同时跑一遍,对比两个模型输出。同一个因果方向上如果两个模型都得出相同的结论,汇报时的底气就完全不同了。
我见过一个翻车案例是这样的:某同学用LiNGAM跑出一组结果是“A→B→C”,兴奋地拿去汇报,却忽略了另一个变量D才是真正的混杂源头。后来加入D变量重跑,因果方向整个颠倒。原因就是原始模型遗漏了重要变量,噪声项不再独立,全盘结论就崩塌了。这个案例对我的方法论构建影响很深:LiNGAM适合做“探索性因果发现”,但绝不等于“放之四海而皆准的真理”。最终因果性的确认,还得结合业务逻辑和实验验证。
5. 适用边界、常见误区与项目复盘
我最初学LiNGAM时,因为没搞清楚边界就硬用,浪费了很多时间。这里把实际使用中最容易踩的坑和适用边界整理清楚,遇坑概率能少一半。
5.1 三条最常见的翻车现场
第一个翻车现场是拿非线性数据当线性处理。LiNGAM的前提是线性关系,但很多真实数据的变量之间天然存在非线性,比如用户年龄和购买意愿往往呈倒U形关系。如果直接用线性LiNGAM,模型会把非线性关系很别扭地线性化,输出完全错误的方向。我的经验是:先用散点图观察变量间关系,如果明显弯曲,要么做变换,要么考虑用非线性因果模型。
第二个翻车现场是遗漏混杂变量。理论上LiNGAM假设所有相关变量都被观测到,即无隐藏混杂。实际业务中这几乎是不可能的。比如前文提到分析页面指标时,用户的设备类型或网络环境可能就是隐藏混杂因素。轻则因果系数有偏,重则因果方向完全反转。建议在做因果图解读时,留出“可能存在未观测混杂”的余地,不要轻易把因果图当真理。
第三个翻车现场是数据量不足时硬要跑。LiNGAM对样本量的需求比普通回归高得多,独立性检验在高维小样本下失真严重。我的经验是:变量数量在十万级左右、样本量至少几千才有较好的稳定性。如果只有几百个样本,跑出来的因果顺序每次重采样都变,基本等于白跑。
5.2 适用场景和不适用的场景
LiNGAM最适合的场景其实是那些“不能做实验,只能依赖观测数据”的领域。比如分析医疗档案中的生理指标因果结构、电商后台的用户行为链路、生产线上各项质量指标的因果传递路径。这些场景背后有物理或逻辑机制支撑线性或无环假设,应用起来比较顺畅。
不太适合的场景包括:强循环反馈系统,比如股市变量,价格和成交量互相影响形成循环;有大量隐藏混杂因素且无法观测的场景,比如分析偏社会科学类问题时,潜变量大量存在,LiNGAM直接失效;数据本身近似高斯分布的场景,效果会打折扣。
5.3 遇到变量循环结构时的排查思路
真实业务场景中,我遇到自己数据疑似有环的情况是最难处理的。比如分析“用户满意度”和“复购行为”两个变量时,你会发现满意度提高复购,复购后形成体验又会反过来改变满意度——这在业务逻辑上就是循环结构。
我的处理思路是先尝试分辨两个行为是否真的发生在同一时间尺度上。大多数所谓循环其实是时序问题,比如上一期满意度影响本期复购,本期复购又影响下一期满意度。这种情况其实可以拆成时间序列上的两阶段因果分析,用分时段拆分变量就能化解。LiNGAM也有时序版本的扩展模型,专门处理这类滞后因果问题。
如果拆分时间后循环仍然存在,我会选择弃用LiNGAM,改用动态因果模型或加干预分析的思路。硬扛的结果通常很惨,模型输出的方向在bootstrap中完全不稳定,基本没有参考价值。
5.4 一次完整的模拟项目复盘
我在带某新人时就做了一个很好的教学案例,过程值得分享。当时我们生成了5000个模拟样本,结构设计为A和B共同影响C,C影响D,噪声分别采用指数分布和均匀分布。这个设定是真实的线性非高斯无环结构。
第一步先生成数据:
import numpy as np # 固定随机种子保证可复现 np.random.seed(42) n = 5000 # 外生变量,均匀分布噪声 A = np.random.uniform(0, 1, n) # 第二层,指数分布噪声 B = 0.5 * A + np.random.exponential(1, n) # 第三层,C受到A和B的线性影响 C = 0.6 * A + 0.3 * B + np.random.uniform(0, 1, n) # 最底层 D = 0.8 * C + np.random.exponential(0.5, n) df = pd.DataFrame({'A': A, 'B': B, 'C': C, 'D': D})第二步跑DirectLiNGAM。首次运行就正确得到了因果顺序,各路径系数也和真实设定基本一致。这个过程让该新人直接理解了外生变量识别和残差迭代的威力。
第三步做压力测试。我们把噪声换成高斯分布,重新生成数据并跑同一模型,发现因果顺序每次运行都会变化。这就是“高斯不可识别”概念的活生生演示,比任何公式都更有说服力。
这个模拟项目的结论是:LiNGAM模型的成功有两个隐藏前提,一是前提假设必须满足,二是数据量必须足够支撑独立性检验的稳定性。缺一个条件,模型的威力就无从谈起。
6. 项目实战中的关键细节与操作笔记
实际操作层面的经验,很多东西是论文源码和官方文档里不会写的。这一节算是我的私人操作笔记,全部来自血泪教训。
6.1 数据量级的最低参考线
我用过最小成功案例是1500个样本、5个变量,因果顺序能稳定复现。但变量数增加到20个时,2万样本跑出来的结果才开始稳定。一个经验法则是:样本量至少是变量数量的100到200倍,越接近此下限,应该用越多的bootstrap次数来验证稳定性。
6.2 变量单位多样性对结果的影响
处理数据集时,如果变量的量纲差异巨大,比如一个变量取值范围是0到1,另一个是1万到100万,直接跑模型可能导致数值精度问题。虽然理论上模型不受线性变换影响,但实际求解过程中的数值误差还是存在的。我这里说的不是标准化,而是建议在不对噪声形态产生破坏的前提下,可以考虑适度缩放变量。稳妥做法是先把每个变量的原始分布形态保存下来,做完模型分析后再换算回原单位解释系数。
6.3 独立性检验方法的选择
DirectLiNGAM的独立性检验有多种实现选项。比如使用基于互信息的方法或基于距离相关的方法。实际操作中不同的检验方法会带来完全不同的结果质量。我自己的对比实验结论是:样本量在5000以上时,用基于核函数的检验方法更稳定;小样本时反而用简单的相关检验更抗噪。这里没有绝对最优,只有针对数据规模的最合适选择。
6.4 因果序的置信度评估
bootstrap之外,我还会在每次bootstrap里记录因果顺序的出现频率,绘制成一个顺序“热度图”。这个热度图能直观看到哪些顺序是铁板钉钉的,哪些顺序的排名在样本间摇摆不定。这个做法比只看系数表更实用,能帮助你精准识别哪些变量对之间的因果关系值得深究。
7. 与其他因果推断方法的横向对比
很多刚接触因果推断的朋友,面对一堆方法无从下手。这里我把和LiNGAM最容易混淆的几个方法摆在一起比较,方便做选型。
7.1 与基于条件独立性的算法对比
PC算法和FCI算法是传统派代表,它们通过条件独立性检验来剪枝和定向。这类方法的优势是不需要数据满足特定分布形态,对线性和噪声分布都很宽容。代价是只能把因果结构识别到马尔可夫等价类,很多因果方向的箭头仍然是未定向的。简单说,PC算法回答“哪些变量可能有关联”,LiNGAM回答“关联的方向到底是从谁到谁”。
7.2 与基于打分搜索的方法对比
以贝叶斯网络结构学习为代表的打分搜索法,比如GES、BDeu分数,它的思路是在所有可能的图结构中打分搜索最优结构。优点是灵活,能处理非线性关系和非高斯分布;缺点是高维空间下搜索计算量极大,而且容易陷入局部最优。LiNGAM的线性假设换取了解析式求解的高效性和稳定性。
7.3 与基于干预实验的方法对比
RCT随机对照实验是因果推断的“金标准”,通过随机分组打破混淆,得到无偏因果效应。但做实验的成本高、周期长,甚至很多场景从伦理上无法开展。LiNGAM的价值在于:有些答案不一定非要通过实验才能获得,在某些良好条件下,纯观测数据也能给出因果方向性的强有力证据。
7.4 选型决策建议
我的经验是:如果数据线性度好、非高斯性明显、变量数可控,首选LiNGAM;如果数据关系未知、非高斯性弱,PC算法先跑一遍摸方向;如果有条件做干预实验,直接做实验,观测数据方法只能当辅助。
8. 开箱即用的工具与仿真验证
实操部分最后分享一下工具链和仿真验证方法。工具选对了,模型跑起来顺畅不少。
8.1 Python生态的lingam库
lingam库是目前Python生态最成熟、最好上手的实现。官方文档例子里就有DirectLiNGAM、ICA-LiNGAM、VarLiNGAM等多个变种。安装方式很简单:
pip install lingam我个人强烈建议不要直接用ICA-LiNGAM版本,它在2010年前后比较主流,但实际迭代稳定性不如DirectLiNGAM。除非你是为了复现早期论文结果,否则DirectLiNGAM是首选。
8.2 手机上看因果图的呈现方式
提到“看因果图”,很多读者以为非得用Tableau或Neo4j这类重型工具,我的实测经验是后续验证需求不大时,一个小技巧就能做到。由于lingam库直接返回邻接矩阵,其实可以导成Graphviz格式并在本地直接渲染,几分钟就能看清结构。不过要留着分析现场的话,还是建议存一份带图结构的HTML文件,方便随时回看。我的习惯是生成SVG,直接放到汇报文档里。
8.3 一分钟仿真验证脚本
我在这里放一个可以直接复制使用的仿真验证脚本,建议每次换新数据集时都先用它自检一遍工作流是否正常:
import numpy as np import pandas as pd import lingam from lingam.utils import make_dot np.random.seed(7) n = 3000 # 已知真实因果结构 x1 = np.random.uniform(0, 2, n) x2 = 0.7 * x1 + np.random.exponential(0.8, n) x3 = 0.4 * x1 + 0.6 * x2 + np.random.uniform(0, 1, n) df = pd.DataFrame({'x1': x1, 'x2': x2, 'x3': x3}) model = lingam.DirectLiNGAM() model.fit(df) print('Causal order:', model.causal_order_) print('Adjacency matrix:\n', model.adjacency_matrix_) dot = make_dot(model.adjacency_matrix_, labels=['x1', 'x2', 'x3']) dot.save('graph_result')输出如果正确识别出x1最靠前、x3最靠后,说明工作流没有异常,这时再跑真实业务数据才靠谱。
9. 实战问题排查清单
整理一份排查速查表,都是我在实际使用中日积月累的问题和解决方案。
| 问题现象 | 可能原因 | 排查方法 | 解决建议 |
|---|---|---|---|
| 因果顺序每次运行都不同 | 数据量太少 | 检查样本量与变量数比例 | 增加样本或减少变量数 |
| 结果与业务常识冲突很大 | 存在未观测混杂 | 检查是否漏了关键变量 | 补充变量或改用其他方法 |
| 非高斯检验全部拒绝但结果不稳定 | 数据存在较强非线性 | 画散点图检视关系 | 考虑非线性扩展版本 |
| 变量间明显有循环逻辑 | 模型前提被违反 | 画图检查DAG结构 | 拆时间序列或放弃该方法 |
| 某一变量的独立性检验失效 | 存在异常值或测量噪声 | 检查箱线图和分布图 | 截尾或剔除异常值 |
| 因果顺序出来了但系数为0 | 变量实际无直接效应 | 检查路径是否存在中介 | 尝试加中间变量再验证 |
| 和PC算法结论完全不同 | 方法假设不同 | 重跑两种方法对比前提条件 | 以适合场景假定的结果为准 |
这张表的核心就是一句话:模型假设被满足到什么程度,结果就可信到什么程度。
10. 最后说几句实操体会
我自己从一开始把LiNGAM当成一个可以拿数据“一键出真相”的黑盒,到后来逐渐理解它其实是在特定结构假设下的一种高效推断工具,这个过程走了不少弯路。现在回头看,最值得记住的一条经验是:因果发现方法输出的“因果图”,本质上是对数据生成机制的某种猜想,而不是最终真理。LiNGAM的价值在于它把“不可识别”的经典困局撕开了一道口子,但这道口子的大小取决于数据本身有多接近它的假设。
用LiNGAM跑真实业务数据前,花几分钟检查一下非高斯性和线性假设是否基本成立;跑完结果后,别忘了用bootstrap验证稳定性。做这两件事,能让你的因果结论在汇报和交付时可靠得多。
另外再多提一句后续可以怎么做。现在非线性版本和时序版本的成套工具已经比较成熟了,我最近就在把时间序列版本应用到用户行为追踪数据上。如果你和我一样,数据里充满反馈回路和滞后效应,不妨去研究一下时序版的扩展方案。在它性能允许的前提下,通常能拿到比静态分析更符合业务直觉的结果。
因果推断这条路确实不好走,但每走一步都能看到比相关分析更接近本质的东西。希望这篇文章能帮你少踩几个坑。