橘智橘智
FakeOrange
预计阅读时间:8分钟13秒

偏相关可能是数据科学中最被低估的工具

重新认识相关性

0
0


前言


本文属于搬运内容,原作者:Samuele Mazzanti, 原文链接。


本文代码均可在Github中的Notebook中找到!


让我认识一位数据科学中的新朋友 —— partial correlation吧!



正文


相关性在数据科学家中口碑不一。时不时就能看到一些夸张的标题,比如“相关性已死”、“再见相关性”、“相关性的替代品来了”等等。


但现实是:相关性仍然活得好好的。因为在实际应用中,它是衡量两个变量之间关系强度的一个非常好用的代理指标,而且简单易用,几乎无可替代


话虽如此,相关性确实有一个严重的缺点:它是单变量度量,不能考虑其他变量可能对测量结果产生的影响。这也正是统计学中那句著名警句的由来:“相关性不代表因果关系。”


幸运的是,有一个推广版本叫做偏相关(Partial Correlation),它保留了简单相关性的所有优点,同时解决了它的主要局限。


然而令人惊讶的是,偏相关至今仍鲜为人知。它的冷门程度可以从一个事实看出——在Python中,只有一个名为 Pingouin 的库实现了它,而这个库并不是大多数数据科学家常用的工具。


在本文中,我将解释为什么偏相关(这个可能是数据科学中最被低估的工具)其实非常强大,值得我们深入了解和使用。



数据集介绍


我们将使用一个名为**“国家纵向调查:青年男性队列(National Longitudinal Survey Young Men Cohort)”的数据集。请注意,这些数据收集于1981年**,所以并不能代表当前的现实情况。但用来做练习已经足够了。


该数据集可以通过 Python 中的 causaldata 库获取,该库基于 MIT 许可证开源。


import causaldata
import pandas as pd

df = pd.concat([
    causaldata.close_college.load_pandas().exog,
    causaldata.close_college.load_pandas().endog], axis=1).dropna().rename({
        "lwage": "Wage",
        "educ": "Education",
        "exper": "Experience",
        "black": "Black",
        "south": "South",
        "married": "Married",
        "smsa": "Urban",
        "nearc4": "NearCollege"}, axis=1)


这个数据集包含3,010行(每行代表一位美国年轻男性),和8个变量(描述这些个体的特征)。


这8个变量包括:

  • Wage:工资(单位:美元)
  • Education:受教育年限
  • Experience:工作经验年限
  • Black:是否为黑人
  • South:是否居住在美国南部
  • Married:是否已婚
  • Urban:是否生活在城市
  • NearCollege:所在县是否有一所四年制大学


我们的目标是用其余7个变量来解释和预测Wage(工资)



从简单相关性开始


我们先从计算每个自变量与目标变量之间的简单相关性开始:


df.corr()["Wage"]


我个人喜欢用图来展示数据,因此我们来绘制一张图表,展示每个变量与工资(Wage)之间的相关系数(纵线表示置信区间)。为了便于阅读,我将这些变量按照与工资的绝对相关程度从高到低进行排序。


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/14cfimage.png


图示:每个变量与工资的简单相关性。


一些结果是符合常识的(例如工资与教育程度呈正相关),但也有一些看起来与我们的世界认知不符

比如:工作经验(Experience)怎么可能与工资没有相关性?

我们当然会预期,工作经验越多,工资越高。然而,在结果中我们却观察到了零相关性


又比如,我们本以为“居住地附近是否有大学(NearCollege)”与工资没啥关系。但我们却观察到了正相关


我们之所以能够注意到这些矛盾,是因为人类倾向于以因果方式进行推理


问题的根源在于:简单相关性是一种单变量度量方式,它无法考虑其他变量对我们感兴趣变量间关系的干扰。这正是“相关性不代表因果性”这句话的本质含义。

通常的解决方法是什么?


我们通常会转向线性回归,这被认为是因果推断的黄金标准



迈向多变量分析:线性回归

和相关性一样,线性回归本质上也是线性的。但它有一个关键优势:它是多变量的(Multivariate)

这意味着我们不用担心其他变量“隐性地”影响我们关注的变量之间的关系。因为这些变量已经包含在模型中,它们的影响已经被“隔离”开了。

我们来在数据集上跑一下线性回归:

import statsmodels.api as sm

sm.OLS(
  exog=sm.add_constant(df.drop("Wage", axis=1)),  # 自变量加入常数项
  endog=df["Wage"]  # 因变量
).fit().summary()


我们得到了以下的回归系数及其置信区间


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/c2b0image.png


图示:线性回归系数。


相比简单相关性,线性回归系数的正负号更符合我们的常识

  • 例如:Experience 的系数现在是正的,
  • 而 NearCollege 的系数不再显著。


因此,我们现在可以知道每个变量的方向性影响,也就是说:当一个变量增加时,它对工资是正向影响还是负向影响



但是如果我们想要知道变量的“相关性强弱”呢?


我们可能会想:


“我不光想知道变量是正影响还是负影响,我还想知道哪一个变量更相关,谁的影响更大?”


这正是相关性非常擅长的地方,对吧?

因为相关系数是一个**-1 到 1 之间的标准化值**,非常便于在不同变量之间进行比较。

回归系数无法用于这种比较

它们每个都有不同的单位和尺度——根本没法放在一起比较

当然了,我们也可以计算一些特征重要性指标,或者使用标准化回归系数等变通方法。但本质上,没有什么比“相关性”更具有可解释性


理想的情况是,我们想要一种度量方式,它兼具以下两个优点:

  1. 简单相关性的可解释性;
  2. 线性回归中排除其他变量干扰的能力。


幸运的是,这种度量方式确实存在,那就是——偏相关(Partial Correlation)



引入偏相关(Partial Correlation)


为了引入偏相关这个概念,我们先回到之前在观察简单相关性时让我们感到疑惑的一点。

我们看到,Education(教育)与 Wage(工资)呈正相关(这是符合常识的),但Experience(工作经验)与 Wage 却不相关(这就令人不解了)。

那么我们再来仔细看看这三者之间的相关系数:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/fec0image.png


图示:教育、经验与工资之间的相关系数。


那为什么Education 与 Experience 有那么强的负相关呢?


从理论上讲,一个人的教育年限和工作经验年限之间不应该有那么强的相关性

但请记住:这个数据集只包含年轻男性

通常情况下,如果你还年轻,你要么是花了很多年上学而刚刚开始工作,要么是早早进入职场积累了不少经验。

所以在这个数据集中,Education 与 Experience 呈强烈负相关是有背景合理性的。

问题来了:由于 Education 与 Wage 也有正相关,那么它就影响了 Experience 与 Wage 的关系

在统计学术语中,我们称 Education 是 Experience 与 Wage 的混杂因子(Confounder)

我们需要一种方法,来测量 Experience 与 Wage 之间的相关性,同时消除 Education 对这两个变量的影响

这正是**偏相关(Partial Correlation)**所做的事情。



偏相关的机制(Partial Correlation Under the Hood)


我们先介绍一下偏相关的计算算法,然后再用直觉来解释它的含义。


下面是计算“Experience 与 Wage 的偏相关(控制 Education 影响)”的三个步骤:

  1. 拟合两个线性模型: Experience ~ Education Wage ~ Education
  2. 分别计算这两个模型的残差(真实值 - 预测值)
  3. 计算这两个残差之间的简单相关系数


这段话可能读起来有点抽象,但代码往往比文字更清晰。以下是这三步在 Python 中的具体实现:


from sklearn.linear_model import LinearRegression

# 第一步:拟合两个线性模型
lr_experience = LinearRegression().fit(X=df[["Education"]], y=df["Experience"])
lr_wage = LinearRegression().fit(X=df[["Education"]], y=df["Wage"])

# 第二步:计算残差
res_experience = df["Experience"] - lr_experience.predict(X=df[["Education"]])
res_wage = df["Wage"] - lr_wage.predict(X=df[["Education"]])

# 第三步:计算残差的相关性,即偏相关系数
partial_correlation = res_experience.corr(res_wage)


你可能会问:为什么要做这几步操作?

一开始听起来或许有些令人困惑,但如果我们用一个实际样本点来思考,就会更容易理解。

比如说,我们有一个人,他受教育年限是 15 年。

根据我们在第一步中训练出的两个线性模型,我们就可以基于他的教育水平预测出他的工作经验和工资。


pred_experience = lr_experience.predict([[15]])
pred_wage = lr_wage.predict([[15]])


我们来把这个预测结果画到一个二维图上:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/dbb6image.png


图示:根据 Education 预测出的 Experience 和 Wage

现在这些只是预测值。但对于这个人,我们同时也有真实的工作经验和真实的工资,所以我们可以将真实值与预测值进行比较。

两者的差就是所谓的残差(residual)


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/e133image.png


图示:Experience 和 Wage 的残差


因此,这个人的工作经验少于预期(残差为负),而工资高于预期(残差为正)。换句话说,在控制了教育年限之后,对这个人来说,Experience 与 Wage 呈负相关

更普遍地,我们可以根据“实际位置相对于预测位置”所在的象限,来将所有样本分为四种可能情况:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/bbf3image.png


图示:Experience 与 Wage 残差的四个象限


  • 如果大多数人落在第 I 象限和第 III 象限(即Experience 和 Wage 的残差同号): 那说明:Experience 高于预期时,Wage 也高于预期;反之亦然。 在这种情况下,Experience 与 Wage 的偏相关为正(在控制 Education 的前提下)。
  • 如果大多数人落在第 II 象限和第 IV 象限(即Experience 和 Wage 的残差异号): 则说明:Experience 高于预期时,Wage 却低于预期;反之亦然。 这时,偏相关为负。


如果你喜欢公式化的表达,下面是皮尔逊相关系数的计算公式:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/1560image.png


图示:皮尔逊相关系数公式


请记住,我们此处是计算残差之间的相关性,而残差的平均值是人为设定为 0 的。

所以,如果大多数人落在第 I 和第 III 象限,分子为正,即偏相关为正;

如果大多数人落在第 II 和第 IV 象限,分子为负,即偏相关为负。


现在我们也计算出了偏相关,我们对这个问题就有了更清晰的认识:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/99b7image.png


图示:各种相关系数对比


  • 原本的简单相关性中,Experience 与 Wage 的相关性接近于 0(1%),
  • 但在控制了 Education 之后,偏相关为 30%,是一个正向相关,这也正符合我们的直觉。


值得注意的是,当我们将 Education 的影响“扣除”之后,它与 Experience 和 Wage 都不再相关了。

这正是“控制某个变量”的定义:在控制之后,该变量不再是混杂因子(confounder)


接下来,我们将对所有其他变量也进行类似的对比,比较它们的简单相关性与偏相关性



计算所有变量的偏相关系数


与其手动逐个进行残差回归并计算相关性,我们不如直接使用 Python 中的 pingouin 库,它提供了一个非常方便的函数:partial_corr

此外,我们不仅可以控制单个混杂变量,还可以选择控制所有其他变量

例如,要计算 Experience 与 Wage 的偏相关性(控制除了它们俩之外的所有变量),可以这样写:


from pingouin import partial_corr

partial_corr(
    data=df, 
    x="Experience", 
    y="Wage",
    covar=[c for c in df.columns if c not in ("Experience", "Wage")]
)


重复上述操作,分别对我们所有的 7 个自变量进行处理,我们就能获得每个变量与 Wage 的偏相关系数

然后我们可以将它们与之前绘制的简单相关性进行对比:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/41e5image.png


图示:每个变量与 Wage 的偏相关(控制所有其余变量之后)


从图中可以看到,偏相关有时与简单相关相似,有时则差异很大


  • Experience:简单相关性接近 0,而偏相关却显著为正(正如我们刚才分析的)。
  • NearCollege:简单相关为正,但偏相关为 0。
  • Black 和 South:偏相关仍为负,但比简单相关弱很多。
  • Education、Urban 和 Married:偏相关与简单相关的差别非常小,可以忽略不计。


控制所有变量的方法非常实用,但我们还可以更进一步

实际上,每个变量真正相关的混杂因子通常不会超过两三个
识别出这些关键混杂变量,有助于我们更深入地理解自变量与目标变量之间的关系网络



如何找出最关键的混杂因子?


我们可以通过类似**“前向选择”(forward selection)的方式,来找出对某个变量来说最重要的混杂因子(confounders)**。

具体做法如下:


  1. 从一个空的协变量集合开始;
  2. 然后,一次只添加一个变量到这个集合中,并测量此时的偏相关系数;
  3. 找出对偏相关影响最大的变量,将其加入协变量集合;
  4. 重复以上步骤,直到所有变量都被加入为止。


比如,我们拿 Experience 与 Wage 的相关性做这个过程时,最终的协变量选择顺序如下图所示:


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/aaecimage.png


图示:随着协变量的加入,偏相关系数的变化


我们一旦将 Education 加入协变量中,偏相关立即从 1% 跃升至 30%(这点我们之前已经见过了)。

但随后加入其他变量时,对偏相关系数的影响就微乎其微了。

这说明:Education 是 Experience 与 Wage 之间的唯一主要混杂因子


我们再尝试看看另一个变量:NearCollege 与 Wage 的偏相关


data/78df2c1f-e442-415d-a382-fa7925af0c4b/291fae56-3a1d-4829-8cec-3d7d836dc27c/d365image.png


图示:NearCollege 与 Wage 之间偏相关的协变量选择过程


这个过程带来了非常有价值的见解。

它不仅说明:在控制所有变量之后,NearCollege 与 Wage 的相关性从 16% 降到了仅 2%;
更进一步的是,它揭示了这个变化主要是由两个变量引起的:Urban 和 South


这个结果很有道理:

  • 居住在城市地区(Urban)与 NearCollege 呈正相关;
  • 而居住在美国南部(South)与 NearCollege 呈负相关;


因此,NearCollege 无意中“吸收”了这两个变量与工资之间的部分关系

除非我们控制 Urban 和 South,这样偏相关才会大幅下降,也正是我们本来就预期的。


单靠线性回归,我们无法达到如此深度的变量关系理解

只有通过偏相关和混杂因子的识别,我们才能更精细地揭示变量间真正的相互影响。


感谢阅读!

评论