斯皮尔曼秩相关系数
斯皮尔曼秩相关系数可以用于检测两组数据是否同向移动,即其中一组数据增加(减少)时,另一组数据是否跟着增加(减少)。这比线性关系更加广泛:例如,$y=e^x$是一个单调函数,但不是一个线性函数。因此,在计算时,我们不是直接使用原始数据,而是数据的秩。 特别是当数据单位不统一时(那么他们自然就不存在线性关系),这种方法非常有用。比如,一块正方形土地的价格和它的边长之间一般不成线性关系,因为按照常理,价格应该跟面积线性相关而不是边长。此外,在对回归模型参数的显著性进行检定时,通常需要对观测值的分布做一些假定,例如使用t分布就需要观测值服从正态分布,但有的数据集不一定满足我们所做的假设,从而无法使用,但是斯皮尔曼秩相关系数就不需要这些假定,仍然可以使用。
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
import math
import pandas as pd
# 对数据进行分级的一个例子
l = [10, 9, 5, 7, 5]
print '原始数据: ', l
print '秩: ', list(stats.rankdata(l, method='average'))
原始数据: [10, 9, 5, 7, 5] 秩: [5.0, 4.0, 1.5, 3.0, 1.5]
用$r_S$表示斯皮尔曼秩相关系数 要计算两个数据集X,Y(每个里面包含n个数据)的等级,使用公式 $$r_S = 1 - \frac{6 \sum_{i=1}^n d_i^2}{n(n^2 - 1)}$$
$d_i$是第i对数据的等级之差,即$X_i - Y_i$.
这个结果总是在$-1$到$1$之间。结果为正代表变量间存在正相关,结果为负就表示负相关。结果为0代表两组变量之间没有任何额单调性关系,不过这并不是说它们之间没有任何的相关关系,比如,对于两组时间序列X和Y,Y是X滞后两期的变量,显然这两组变量是相关的,但是它们的$r_S$可以非常接近于0
## 示例
n = 100
def compare_correlation_and_spearman_rank(n, noise):
X = np.random.poisson(size=n)
Y = np.exp(X) + noise * np.random.normal(size=n)
Xrank = stats.rankdata(X, method='average')
# n-2是指倒数第二个元素
Yrank = stats.rankdata(Y, method='average')
diffs = Xrank - Yrank # 这个地方Xrank和Yrank的顺序不重要,因为要对它们进行平方
r_s = 1 - 6*sum(diffs*diffs)/(n*(n**2 - 1))
c_c = np.corrcoef(X, Y)[0,1]
return r_s, c_c
experiments = 1000
spearman_dist = np.ndarray(experiments)
correlation_dist = np.ndarray(experiments)
for i in range(experiments):
r_s, c_c = compare_correlation_and_spearman_rank(n, 1.0)
spearman_dist[i] = r_s
correlation_dist[i] = c_c
print '斯皮尔曼秩相关系数: ' + str(np.mean(spearman_dist))
# 与通常意义上的相关系数进行对比
print '通常意义下的相关系数: ' + str(np.mean(correlation_dist))
斯皮尔曼秩相关系数: 0.877291422142 通常意义下的相关系数: 0.769284543469
从泊松分布中取一组数据(不服从正态分布),然后令$Y = e^X + \epsilon$,$\epsilon$是另一个泊松分布的均值,再求出这两组数据的斯皮尔曼秩相关系数和它们的相关系数,这样重复进行很多次。 由于$e^X$会产生很多与其它的数据偏离很远的数据,因此我们用它来模拟数据集中的极端值。斯皮尔曼秩相关系数可以有效减弱极端值的影响,从而对变量间的相关性做出更好的衡量。而通常意义上的相关系数受极端值的影响比较大,经常会低估变量间的相关性。
我们来看一看X,Y间的相关性并把用斯皮尔曼的方法和一般的方法得出的结果进行比较
plt.hist(spearman_dist, bins=50, alpha=0.5)
plt.hist(correlation_dist, bins=50, alpha=0.5)
plt.legend(['Spearman Rank', 'Regular Correlation'])
plt.xlabel('Correlation Coefficient')
plt.ylabel('Frequency');
现在,我们再来看当在数据中加入一些干扰时,会出现什么情况。
n = 100
noises = np.linspace(0, 3, 30)
experiments = 100
spearman = np.ndarray(len(noises))
correlation = np.ndarray(len(noises))
for i in range(len(noises)):
# Run many experiments for each noise setting
rank_coef = 0.0
corr_coef = 0.0
noise = noises[i]
for j in range(experiments):
r_s, c_c = compare_correlation_and_spearman_rank(n, noise)
rank_coef += r_s
corr_coef += c_c
spearman[i] = rank_coef/experiments
correlation[i] = corr_coef/experiments
plt.scatter(noises, spearman, color='r')
plt.scatter(noises, correlation)
plt.legend(['Spearman', 'regular'])
plt.xlabel('amount of noise')
plt.ylabel('average correlational coefficient')
<matplotlib.text.Text at 0x7f1d7739a810>
可以看到,斯皮尔曼秩相关系数在不同程度的干扰下基本都能较好的衡量相关性。不过在干扰程度特别强的时候,它似乎会比通常意义上的相关系数表现的要差
有时我们会碰到这样的情况,两组变量相互影响,但是会有一个延迟。让我们来看看加入延迟后会出现什么现象。
n = 100
X = np.random.rand(n)
Xrank = stats.rankdata(X, method='average')
# n-2 is the second to last element
Yrank = stats.rankdata([1,1] + list(X[:(n-2)]), method='average')
diffs = Xrank - Yrank # order doesn't matter since we'll be squaring these values
r_s = 1 - 6*sum(diffs*diffs)/(n*(n**2 - 1))
print r_s
-0.0991209120912
显然,这种相关性没有被捕捉到。因此,在存在延迟时,要同时使用斯皮尔曼秩相关系数和通常意义上的相关系数来避免遗漏,同时,还应该去掉延迟,用多组平行数据进行检测。
我们也可以使用scipy.stats
库里的spearmanr
函数
# 生成两组随机数
np.random.seed(161)
X = np.random.rand(10)
Y = np.random.rand(10)
r_s = stats.spearmanr(X, Y)
print '斯皮尔曼秩相关系数: ', r_s[0]
print 'p-value: ', r_s[1]
斯皮尔曼秩相关系数: 0.236363636364 p-value: 0.510885317515
现在我们有了定义的$r_S$,但是它的含义到底是什么呢?它取正值时,我们知道这表示变量间不是负相关。它的值不大,那么我们知道变量间的正相关性不是很强,但是一眼看上去我们很难判断这种相关关系是否显著。幸运的是, 斯皮尔曼同时也会计算相关系数的p-value和样本大小。我们可以看到此处的p-value大于0.05,因此,我们不能说X和Y是相关的。
现在我们知道了斯皮尔曼等级相关系数的原理,那么我们就来用一个具体的实例来演示一下。比如,可以检测一个共同基金的费用与它三年的夏普比是否相关。也就是说,一个共同基金花费越多,是否意味着它的风险越低或者收益率越高?这个问题就可以使用斯皮尔曼等级相关系数来检验,此处我们默认p-value为0.05。
感谢Matthew Madurski提供的数据。获取数据的步骤:
mutual_fund_data= pd.read_csv('mutual_fund_data.csv')
expense = mutual_fund_data['Annual Expense Ratio'].values
sharpe = mutual_fund_data['Three Year Sharpe Ratio'].values
plt.scatter(expense, sharpe)
plt.xlabel('Expense Ratio')
plt.ylabel('Sharpe Ratio')
r_S = stats.spearmanr(expense, sharpe)
print '斯皮尔曼秩相关系数: ', r_S[0]
print 'p-value: ', r_S[1]
斯皮尔曼秩相关系数: -0.237573932355 p-value: 0.0167465097116
求得的p-value小于0.05,说明原假设是正确的。花费确实与夏普比相关,且从结果来看,它们之间是成负相关的。然而,这里有一个奇怪的地方,从图中可以看到,数据有聚集的现象。从上图来看,有些花费多的共同基金夏普比比较低,而大多数的共同基金的夏普比与花费没有明显的相关关系。要弄清楚这里具体是什么原因,还需要进一步的分析。
以计算机/互联网行业的股票为例,假设这个行业中的股票上个月的平均收益率与这个月的平均收益率成正相关,现在我们来检测这个假设是否成立。
symbol_list =get_industry_stocks('I64')
# 获取上个月的收益率
start = '2015-08-01'
end = '2015-09-01'
historical_returns = get_price(symbol_list, fields='price', start_date=start, end_date=end).pct_change()[0:]
# 计算各只股票的平均收益率
scores = np.mean(historical_returns)
print 'average return of last month\n'
print scores
print '\n'
#获取这个月的收益率
start = '2015-09-01'
end = '2015-10-01'
walk_forward_returns = get_price(symbol_list, fields='price', start_date=start, end_date=end).pct_change()[0:]
#计算各只股票的平均收益率
walk_forward_returns = np.mean(walk_forward_returns)
print 'average return of this month\n'
print walk_forward_returns
print '\n'
plt.scatter(scores, walk_forward_returns)
plt.xlabel('average return of last month')
plt.ylabel('average return of this month')
r_s = stats.spearmanr(scores, walk_forward_returns)
print '相关系数: ' + str(r_s[0])
print 'p-value: ' + str(r_s[1])
average return of last month price 000503.XSHE -0.019558 002095.XSHE -0.005533 002174.XSHE 0.000000 002315.XSHE -0.007950 002354.XSHE 0.004093 002439.XSHE -0.011898 002467.XSHE -0.015432 300059.XSHE -0.012561 300104.XSHE -0.012610 300113.XSHE -0.024175 300431.XSHE -0.017393 300467.XSHE 0.000000 300226.XSHE -0.009058 300295.XSHE -0.009890 300383.XSHE 0.000000 300392.XSHE -0.014040 300418.XSHE -0.032626 600804.XSHG -0.007636 603000.XSHG -0.007722 average return of this month price 000503.XSHE 0.005466 002095.XSHE 0.000735 002174.XSHE 0.000000 002315.XSHE 0.006041 002354.XSHE 0.004739 002439.XSHE 0.016386 002467.XSHE 0.007491 300059.XSHE 0.005429 300104.XSHE 0.009936 300113.XSHE 0.016674 300431.XSHE 0.026902 300467.XSHE 0.000000 300226.XSHE 0.021097 300295.XSHE 0.012210 300383.XSHE 0.000000 300392.XSHE 0.022171 300418.XSHE 0.017337 600804.XSHG 0.009990 603000.XSHG -0.001316 相关系数: -0.68485915493 p-value: 0.00121542282477
p-value小于0.05,而相关系数为负。显然,假设是不成立的。也就是说采用斯皮尔曼等级相关系数检测的结果表明计算机/互联网行业的股票在2015年9月到10月的平均收益率与上一个与月的平均收益率是成负相关的。
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...