斯皮尔曼等级相关系数(Spearman Rank Correlation)是一种非参数统计方法,用于衡量两个变量之间的单调关系。与皮尔逊相关系数不同,斯皮尔曼相关不要求数据呈线性关系,也不要求数据服从正态分布,因此适用范围更广。
一、基本概念与原理#
1.1 什么是单调关系?#
单调关系指两个变量变化方向的一致性。举例说明:
-
正单调:X增加时Y也增加(可以是线性或非线性)
-
负单调:X增加时Y减少
-
非单调:变化方向不一致
1.2 为什么需要等级相关?#
当数据存在以下情况时适用:
-
非正态分布
-
存在异常值
-
测量尺度不同
-
非线性但单调的关系
与皮尔逊相关系数的对比:
| 指标 | 皮尔逊 | 斯皮尔曼 |
|---|---|---|
| 数据要求 | 线性关系、正态分布 | 单调关系 |
| 异常值敏感度 | 高 | 低 |
| 测量尺度 | 要求相同 | 可不同 |
二、核心公式与计算#
2.1 等级转换方法#
处理重复值的平均等级法:
code
import scipy.stats as stats
data = [85, 90, 78, 90, 92]
print(stats.rankdata(data, method='average')) # [2. 3.5 1. 3.5 5.]2.2 斯皮尔曼公式#
参数说明:
-
为Spearman相关系数
-
为第i对观测值的等级差
-
n 为样本量
手动计算示例:
code
X = [10, 9, 5, 7, 5]
Y = [20, 17, 11, 15, 13]
# 转换等级
X_rank = [5,4,1.5,3,1.5]
Y_rank = [5,4,1,3,2]
# 计算差值平方和
d_sq = sum([(x-y)**2 for x,y in zip(X_rank,Y_rank)]) # 0.5
rho = 1 - 6*0.5/(5*(25-1)) # 0.975三、实战应用#
3.1 使用scipy快速计算#
code
import numpy as np
from scipy import stats
x = np.random.normal(size=100)
y = np.exp(x) + np.random.normal(scale=0.5, size=100)
corr, p_value = stats.spearmanr(x, y)
print(f"相关系数: {corr:.3f}, p值: {p_value:.4f}")3.2 金融数据案例(使用yfinance)#
code
import yfinance as yf
import pandas as pd
# 获取标普500和道琼斯指数数据
data = yf.download(['^GSPC', '^DJI'], start='2020-01-01', end='2023-01-01')['Close']
returns = data.pct_change().dropna()
# 计算滚动三个月相关性
rolling_corr = returns.rolling(60).corr(pairwise=True).iloc[:,0,1]
# 可视化
import matplotlib.pyplot as plt
plt.figure(figsize=(10,6))
rolling_corr.plot(title='3个月滚动斯皮尔曼相关性')
plt.ylabel('相关系数')
plt.show()3.3 因子选股验证#
code
# 获取股票数据
symbols = ['AAPL', 'MSFT', 'GOOG', 'AMZN', 'META']
data = yf.download(symbols, period='1y')['Close']
# 计算月度收益
monthly_returns = data.resample('M').last().pct_change()
# 生成因子(过去三个月动量)
factor = monthly_returns.rolling(3).mean().shift(1)
# 计算等级相关性
correlations = []
for i in range(3, len(monthly_returns)):
current_factor = factor.iloc[i].rank()
next_return = monthly_returns.iloc[i].rank()
corr = stats.spearmanr(current_factor, next_return).correlation
correlations.append(corr)
print(f"平均前瞻相关性: {np.mean(correlations):.3f}")四、进阶话题#
4.1 时间延迟相关性检测#
code
def detect_lag_correlation(x, y, max_lag=5):
correlations = []
for lag in range(max_lag+1):
shifted_y = y.shift(-lag).dropna()
common_index = x.index.intersection(shifted_y.index)
corr = stats.spearmanr(x.loc[common_index], shifted_y.loc[common_index]).correlation
correlations.append((lag, corr))
return pd.DataFrame(correlations, columns=['Lag', 'Correlation'])
# 使用示例
np.random.seed(42)
x = pd.Series(np.random.rand(100))
y = x.shift(2).iloc[2:].reset_index(drop=True) + np.random.normal(scale=0.1, size=98)
results = detect_lag_correlation(x, y)
print(results.sort_values('Correlation', ascending=False))4.2 显著性检验#
p 值的解读指南:
-
p < 0.01:极强证据拒绝零假设
-
0.01 ≤ p < 0.05:强证据
-
0.05 ≤ p < 0.1:弱证据
-
p ≥ 0.1:无显著证据
五、常见问题解答#
Q1:如何处理等值数据?#
当出现相同值时:
-
使用平均等级法(推荐)
-
可选方法:最小/最大等级、随机分配
Q2:样本量要求?#
-
最小样本量:建议n ≥ 5
-
可靠性:n ≥ 20时结果更稳定
Q3:与肯德尔tau的区别?#
两者比较:
| 指标 | 计算方式 | 灵敏度 |
|---|---|---|
| 斯皮尔曼 | 等级差平方 | 对趋势敏感 |
| 肯德尔tau | 一致对比例 | 更稳健 |
练习:
-
下载苹果公司过去一年的股价数据,计算其日收益率与交易量的斯皮尔曼相关性
-
生成两个具有二次关系的变量(y = x² + noise),比较皮尔逊和斯皮尔曼相关系数
-
尝试修改时间延迟检测函数,实现双向延迟检测(正负延迟)
code
# 练习参考答案
# 练习1:
aapl = yf.download('AAPL', period='1y')
aapl['Return'] = aapl['Close'].pct_change()
aapl['Volume'] = aapl['Volume']
corr = stats.spearmanr(aapl['Return'].dropna(), aapl['Volume'].dropna())
print(f"收益率与交易量相关性:{corr.correlation:.3f}")通过本教程,您应该掌握了斯皮尔曼相关系数的核心原理、实现方法及在金融分析中的典型应用。在实际研究中,建议结合可视化分析和统计检验综合判断变量间的关系。