用Pandas在Python中计算Spearman's Rank Correlation Coefficient

1,290 阅读9分钟

简介

本指南是对Spearman等级相关系数、它的数学计算以及通过Python的pandas 库进行计算的介绍。我们将构造各种例子来获得对这个系数的基本理解,并演示如何通过热图来可视化相关矩阵

什么是Spearman等级相关系数?

斯皮尔曼****等级相关系数皮尔逊相关系数密切相关,两者都是一个有界值,从-11 ,表示两个变量之间的相关性

如果你想阅读更多关于替代性相关系数的信息--请阅读我们的《Python中的皮尔逊相关系数指南》

皮尔逊相关系数是使用原始数据值计算的,而斯皮尔曼相关系数是由单个数值的等级计算的。皮尔逊相关系数是对两个变量之间的线性关系的测量,而斯皮尔曼等级相关系数测量的是一对变量之间的单调关系。为了理解斯皮尔曼相关,我们需要对单调函数有一个基本的了解。

单调函数

有单调增加、单调减少和非单调函数。

对于一个单调增加的函数,随着X的增加,Y也会增加(而且它不一定是线性的)。对于一个单调递减的函数,当一个变量增加时,另一个变量就会减少(也不一定是线性的)。非单调函数是指一个变量的数值增加有时会导致另一个变量的数值增加,有时会导致另一个变量的数值减少。

Spearman等级相关系数衡量两个变量之间的单调关系。其数值范围从-1到+1,可以解释为。

  • **+1:**完全的单调增长关系
  • **+0.8:**强单调增长关系
  • +0.2:弱的单调增长关系
  • **0:**非单调的关系
  • **-0.2:**弱的单调递减关系
  • -0.8: 强单调递减关系
  • -**1:**完全的单调递减关系

数学表达式

假设我们有两个随机变量 \(n\) 的观察值,即 \(X\) 和 \(Y\) 。我们首先将两个变量的所有值分别排成 \(X_r\) 和 \(Y_r\)。Spearman等级相关系数用\(r_s\)表示,并通过以下方式计算。

r\_s = rho\_{X\_r,Y\_r} = frac{text{COV}(X\_r,Y\_r)}{text{STD}(X\_r)/text{STD}(Y\_r)} = frac{n\_sum/limits\_{x\_r\\in X\_r , y\_r\\in Y\_r} x\_r y\_r - \\sum\\limits\_{x\_r\\in X\_r}x\_r\\sum\\limits\_{y\_r\\in Y\_r}y\_r}{sqrt{Big(nsum\\limits\_{x\_r\\in X\_r} x\_r^2 -((sum\\limits\_{x\_r\\in X\_r}x\_r)^2\\Big)}\\sqrt{Big(n\\sum\\limits\_{y\_r\\in Y\_r}y\_r^2 - (sum\\limits\_{y\_r\\in Y\_r}y\_r)^2\\Big)}

这里,COV() 是协方差,STD() 是标准差。在我们看到Python计算这个系数的函数之前,让我们用手做一个计算的例子,来理解这个表达式并体会它。

计算实例

假设我们得到了一些随机变量 \(X\) 和 \(Y\) 的观察结果。第一步是将 \(X\)和 \(Y\)转换为 \(X_r\)和 \(Y_r\),这代表它们相应的等级。还需要一些中间值,如下所示。

X = [ - 2 - 1 0 1 2 ] T Y = [ 4 1 3 2 0 ] T X r = [ 1 2 3 4 5 ] T Y r = [ 5 2 4 3 1 ] T X r 2 = [ 1 4 9 16 25 ] T Y r 2 = [ 25 4 16 9 1 ] T X r Y r = [ 5 4 12 12 5 ] T

让我们使用之前的公式来计算Spearman相关性。

r s = 5 ∗ 38 - ( 15 ) ( 15 ) ( 5 ∗ 55 - 15 2 ) ( 5 ∗ 55 - 15 2 ) = 181 532 = - 0.7

很好!不过,手动计算是很耗时的,而计算机的最佳用途就是,为我们计算东西。使用Pandas的内置函数,计算Spearman相关系数是非常简单和直接的。

使用Pandas计算Spearman等级相关系数

各种相关系数,包括Spearman,可以通过Pandas库的corr() 方法来计算。

作为一个输入参数,corr() 函数接受用于计算相关系数的方法(在我们的例子中是spearman )。该方法在一个DataFrame ,例如大小为mxn ,其中每一列代表一个随机变量的值,m 代表每个变量的总样本。

对于n 随机变量,它返回一个nxn 方形矩阵RR(i,j) 表示随机变量ij 之间的Spearman等级相关系数。由于变量与自身的相关系数为1,所有对角线条目(i,i) ,都等于1。简而言之。

R ( i , j ) = { r i , j 如果 i ≠ j 1 否则

请注意,相关矩阵是对称的,因为相关是对称的,也就是说,M(i,j)=M(j,i) 。让我们以上一节的简单例子为例,看看如何使用Pandas的corr() fuction。

import numpy as np
import pandas as pd
import seaborn as sns # For pairplots and heatmaps
import matplotlib.pyplot as plt

我们将使用Pandas进行计算本身,使用Matplotlib和Seaborn进行可视化,使用Numpy对数据进行额外的操作。

下面的代码计算了数据框架x_simple 的Spearman相关矩阵。注意对角线上的1,表示变量与自身的相关系数自然为1

x_simple = pd.DataFrame([(-2,4),(-1,1),(0,3),(1,2),(2,0)],
                        columns=["X","Y"])
my_r = x_simple.corr(method="spearman")
print(my_r)
     X    Y
X  1.0 -0.7
Y -0.7  1.0

相关系数的可视化

考虑到有界强度的表状结构,[-1, 1] --可视化相关系数的一个自然和方便的方法是热图

如果你想阅读更多关于Seaborn中的热图,请阅读我们的《使用Python在Seaborn中绘制热图的终极指南》!

热图是一个由单元格组成的网格,每个单元格根据其数值被赋予一种颜色,这种解释相关矩阵的视觉方式对我们来说比解析数字要容易得多。对于像之前输出的那个小表格--它完全没问题。但是对于大量的变量,要真正解释发生了什么就难多了。

让我们定义一个display_correlation() ,计算相关系数并以热图的形式显示。

def display_correlation(df):
    r = df.corr(method="spearman")
    plt.figure(figsize=(10,6))
    heatmap = sns.heatmap(df.corr(), vmin=-1, 
                      vmax=1, annot=True)
    plt.title("Spearman Correlation")
    return(r)

让我们在我们的r_simple DataFrame上调用display_correlation() ,以可视化Spearman相关度。

r_simple=display_correlation(x_simple)

correlation values

在合成实例上理解斯皮尔曼相关系数

为了理解Spearman相关系数,在我们深入研究更多的自然例子之前,让我们生成几个合成例子,以突出该系数的工作原理。这些例子将帮助我们理解,对于什么类型的关系,这个系数是+1,-1,还是接近于零。

在生成例子之前,我们将创建一个新的辅助函数,plot_data_corr() ,它调用display_correlation() ,并根据X 变量绘制数据。

def plot_data_corr(df,title,color="green"):    
    r = display_correlation(df)
    fig, ax = plt.subplots(nrows=1, ncols=len(df.columns)-1,figsize=(14,3))
    for i in range(1,len(df.columns)):
        ax[i-1].scatter(df["X"],df.values[:,i],color=color)
        ax[i-1].title.set_text(title[i] +'\n r = ' + 
                             "{:.2f}".format(r.values[0,i]))
        ax[i-1].set(xlabel=df.columns[0],ylabel=df.columns[i])
    fig.subplots_adjust(wspace=.7)    
    plt.show()

单调递增函数

让我们使用Numpy生成几个单调递增的函数,并在填入合成数据后看一下DataFrame

seed = 11
rand = np.random.RandomState(seed)
# Create a data frame using various monotonically increasing functions
x_incr = pd.DataFrame({"X":rand.uniform(0,10,100)})
x_incr["Line+"] = x_incr.X*2+1
x_incr["Sq+"] = x_incr.X**2
x_incr["Exp+"] = np.exp(x_incr.X)
x_incr["Cube+"] = (x_incr.X-5)**3

print(x_incr.head())
X线+Sq+Exp+Cube+
01.8026974.6053943.2497166.065985-32.685221
10.1947521.3895050.0379291.215010-110.955110
24.63218510.26437121.457140102.738329-0.049761
37.24933915.49867952.5529201407.17480911.380593
44.2020369.40407217.65710766.822246-0.508101

现在让我们看一下Spearman相关的热图和各种函数与X

plot_data_corr(x_incr,["X","2X+1","$X^2$","$e^X$","$(X-5)^3$"])

correlation heatmap

monotonically increasing functions

我们可以看到,对于所有这些例子,变量之间存在着完全的单调增长关系。无论变量之间是线性关系还是非线性关系,Spearman相关度都是+1。

皮尔逊在这里会产生很多不同的结果,因为它是根据变量之间的线性关系来计算的。

只要Y随着X的增加而增加,那么Spearman Rank Correlation Coefficient就一定1

单调递减函数

让我们在单调递减函数上重复同样的例子。我们将再次生成合成数据并计算Spearman等级相关。首先,让我们看一下DataFrame 的前4行。

# Create a data matrix
x_decr = pd.DataFrame({"X":rand.uniform(0,10,100)})
x_decr["Line-"] = -x_decr.X*2+1
x_decr["Sq-"] = -x_decr.X**2
x_decr["Exp-"] = np.exp(-x_decr.X)
x_decr["Cube-"] = -(x_decr.X-5)**3
x_decr.head()
X线-Sq-解释立方体
03.181872-5.363744-10.1243090.0415086.009985
12.180034-3.360068-4.7525470.11303822.424963
28.449385-15.898771-71.3921120.000214-41.041680
33.021647-5.043294-9.1303500.0487217.743039
44.382207-7.764413-19.2037360.0124980.235792

相关矩阵的热图和变量的曲线图在下面给出。

plot_data_corr(x_decr,["X","-2X+1","$-X^2$","$-e^X$","$-(X-5)^3$"],"blue")

correlation heatmap

monotonically decreasing functions

非单调性函数

下面的例子是关于各种非单调函数的。在DataFrame ,最后一列是独立变量Rand ,它与X 没有关联。

这些例子还应该说明,Spearman相关系数是对两个变量之间关系的一种测量。 单调性两个变量之间的关系。系数为零并不一定表示没有关系,但它确实表示它们之间没有关系。 单调性它们之间的关系。

在生成合成数据之前,我们将定义另一个辅助函数,display_corr_pairs() ,它调用display_correlation() 来显示相关矩阵的热图,然后使用Seaborn库将DataFrame 中的所有变量对相互绘制。

在对角线上,我们将使用map_diag() ,用黄色显示每个变量的柱状图。在对角线的下面,我们将制作一个所有变量对的散点图。由于相关矩阵是对称的,我们不需要对角线以上的图。

我们也来显示皮尔逊相关系数以进行比较。

def display_corr_pairs(df,color="cyan"):
    s = set_title = np.vectorize(lambda ax,r,rho: ax.title.set_text("r = " + 
                                        "{:.2f}".format(r) + 
                                        '\n $\\rho$ = ' + 
                                        "{:.2f}".format(rho)) if ax!=None else None
                            )      

    r = display_correlation(df)
    rho = df.corr(method="pearson")
    g = sns.PairGrid(df,corner=True)
    g.map_diag(plt.hist,color="yellow")
    g.map_lower(sns.scatterplot,color="magenta")
    set_title(g.axes,r,rho)
    plt.subplots_adjust(hspace = 0.6)
    plt.show()    

我们将创建一个非单调的DataFrame,x_non ,用X 的这些函数。

  • 抛物线。\( (X-5)^2 \)

  • 窦。\Sin: (\sin (frac{X}{10}2\pi) \)

  • Frac:\Frac: ( frac{X-5}{(X-5)^2+1})\)

  • Rand:范围为[-1,1]的随机数

下面是x_non 的前4行。

x_non = pd.DataFrame({"X":rand.uniform(0,10,100)})
x_non["Parabola"] = (x_non.X-5)**2
x_non["Sin"] = np.sin(x_non.X/10*2*np.pi)
x_non["Frac"] = (x_non.X-5)/((x_non.X-5)**2+1)
x_non["Rand"] = rand.uniform(-1,1,100)

print(x_non.head())
X抛物线FracRand
00.65446618.8836670.399722-0.2185480.072827
15.7465590.557351-0.4520630.479378-0.818150
26.8793623.532003-0.9249250.414687-0.868501
35.6830580.466569-0.4161240.4657530.337066
46.0372651.075920-0.6065650.4996660.583229

不同数据对之间的Spearman相关系数说明如下。

display_corr_pairs(x_non)

correlation heatmap

non-monotonic functions

这些例子表明,对于哪种类型的数据,Spearman相关系数接近于零,在哪种类型的数据中,它有中间值。另外需要注意的是,Spearman相关系数和Pearson相关系数并不总是相互一致的,所以缺少一个并不意味着缺少另一个。

它们是用来测试数据不同方面的相关性的,不能交替使用。虽然它们在某些情况下会保持一致,但并不总是如此。

林纳鲁德数据集上的斯皮尔曼相关系数

让我们在一个实际的数据集上应用Spearman相关系数。我们从sklearn.datasets 包中选择了名为linnerud 的简单体育锻炼数据集进行演示。

import sklearn.datasets.load_linnerud

下面的代码加载了该数据集,并将目标变量和属性连接到一个DataFrame 。让我们看一下linnerud 数据的前4行。

d=load_linnerud()

dat = pd.DataFrame(d.data,columns=d.feature_names)
alldat=dat.join(pd.DataFrame(d.target,columns=d.target_names) )
alldat.head()
臀部仰卧起坐跳跃体重腰围脉搏
05.0162.060.0191.036.050.0
12.0110.060.0189.037.052.0
212.0101.0101.0193.038.058.0
312.0105.037.0162.035.062.0
413.0155.058.0189.035.046.0

现在,让我们用我们的display_corr_pairs() 函数显示相关对。

display_corr_pairs(alldat)

correlation heatmap

physical exercise dataset correlation analysis

看一下Spearman相关值,我们可以得出有趣的结论,例如。

  • 较高的腰围值意味着体重值的增加(从r=0.81来看)
  • 更多的仰卧起坐有更低的腰围值(从r = -0.72)。
  • 引体向上、仰卧起坐和跳跃似乎与脉搏没有单调的关系,因为相应的r值接近于零。

结论

在本指南中,我们讨论了Spearman等级相关系数,它的数学表达式,以及通过Python的pandas 库进行的计算。

我们在各种合成例子和Linnerrud 数据集上演示了这个系数。Spearman相关系数是计算两个变量之间关系的单调性的理想措施。然而,一个接近零的值并不一定表明这些变量之间没有关联。