3、斯皮尔曼秩相关系数:与皮尔逊的区别、适用场景、代码实现

聊完了皮尔逊,咱们得面对一个现实问题——真实市场数据,很少是干干净净的线性关系

我记得刚入行那会儿,特别喜欢用皮尔逊系数。觉得它简洁、优雅,算出来就是标准答案。直到有一次,我拿它去分析某只小盘股和指数的相关性,结果跑出来一个接近0的值。我当时还挺高兴,觉得找到了一个不跟大盘走的「独立标的」。

结果呢?

回测一跑,亏得我头皮发麻。后来仔细一看,这两者的关系根本不是线性的——指数涨1%,它可能涨3%;指数跌1%,它可能跌5%。皮尔逊对这种「非线性但单调」的关系,基本是瞎的。

从那以后,我的工具箱里就多了一个新家伙——斯皮尔曼秩相关系数

3.1 斯皮尔曼到底在算什么?

说白了,斯皮尔曼不关心你的原始数值是多少。

它只关心一件事:排序

你把两个变量的数据分别排个名次,然后计算这些名次之间的皮尔逊相关系数。嗯,你没看错——斯皮尔曼本质上就是「名次的皮尔逊」。

举个例子:

  • 股票A的收益率:1%, 2%, 3%, 4%, 5%
  • 股票B的收益率:100%, 50%, 30%, 20%, 10%

皮尔逊算出来,这两者可能是负相关。但斯皮尔曼呢?

排名一下:

  • A的排名:1, 2, 3, 4, 5
  • B的排名:5, 4, 3, 2, 1

完美负相关,斯皮尔曼系数 = -1。这才是真实的关系——一个涨得越多,另一个跌得越惨

核心区别一句话:皮尔逊看「数值大小」,斯皮尔曼看「相对顺序」。

3.2 与皮尔逊的三大区别

我习惯从三个维度来区分它们:

维度 皮尔逊 斯皮尔曼
数据要求 连续、正态分布、线性关系 无分布要求,只要求单调关系
对异常值敏感度 极高。一个极端值就能把系数拉偏 低。排名机制天然抗异常值
输出含义 线性相关的方向和强度 单调相关的方向和强度

你想想看,金融市场里有多少数据是完美正态分布的?几乎没有。收益率序列经常有厚尾,偶尔来个黑天鹅,皮尔逊直接就崩了。

我曾在一次风险归因分析中,因为一个极端交易日的数据,导致皮尔逊系数从0.6跳到了0.2。换成斯皮尔曼,只从0.58降到了0.55。嗯,这就是排名的力量。

3.3 什么时候该用斯皮尔曼?

我个人习惯,遇到以下场景会优先考虑斯皮尔曼:

  1. 数据明显不是正态分布——比如收益率、成交量、波动率这些。
  2. 存在明显的异常值——比如某天突然涨停或跌停。
  3. 关系可能是非线性的,但单调——比如规模因子和收益的关系,小市值往往收益更高,但不是线性的。
  4. 数据本身就是排名——比如分析师评级、基金排名等。
一个小技巧:我一般会同时算皮尔逊和斯皮尔曼。如果两者差异很大(比如皮尔逊0.3,斯皮尔曼0.7),说明数据里大概率有非线性关系或者异常值在捣乱。这时候我会停下来,仔细看看数据长什么样。

3.4 避坑指南

我曾经踩过的坑:斯皮尔曼虽然抗异常值,但它不是万能的。如果两个变量之间的关系不是单调的(比如先涨后跌的U型关系),斯皮尔曼也会失效。这时候你需要的是距离相关性或者互信息这类更高级的工具。

另外要注意:斯皮尔曼对样本量有一定要求。样本太少(比如少于10个),排名本身的信息量就不够,算出来的系数波动会很大。我一般要求至少30个样本点才敢用。

3.5 代码实现

直接上代码。我习惯用Python,scipy库已经封装好了:

import numpy as np
import pandas as pd
from scipy.stats import spearmanr, pearsonr

# 模拟数据:非线性但单调的关系
np.random.seed(42)
x = np.random.randn(100)
y = x**3 + np.random.randn(100) * 0.5  # 立方关系,但单调递增

# 计算两种相关系数
pearson_r, _ = pearsonr(x, y)
spearman_r, _ = spearmanr(x, y)

print(f"皮尔逊系数: {pearson_r:.3f}")
print(f"斯皮尔曼系数: {spearman_r:.3f}")

# 输出示例:
# 皮尔逊系数: 0.812
# 斯皮尔曼系数: 0.947

看到了吗?同样的数据,斯皮尔曼能更好地捕捉到这种单调关系。

如果你用的是pandas,更简单:

# 假设df是DataFrame,包含两列 'asset_a' 和 'asset_b'
df = pd.DataFrame({
    'asset_a': np.random.randn(100),
    'asset_b': np.random.randn(100)
})

# 直接算斯皮尔曼
spearman_matrix = df.corr(method='spearman')
print(spearman_matrix)

嗯,一行代码搞定。我经常在探索性分析阶段,先用这个方法快速扫一遍所有资产对的相关性。

3.6 实战中的一个小案例

去年我在做多资产配置时,需要评估黄金和比特币的相关性。如果用皮尔逊,算出来是0.15,感觉两者没什么关系。但直觉告诉我,极端行情下它们可能同涨同跌。

换成斯皮尔曼,系数变成了0.42。为什么?因为黄金和比特币的关系不是线性的——平时各走各的,但遇到流动性危机时,两者都会被抛售。这种「平时无关、极端时相关」的模式,皮尔逊根本抓不住。

所以我现在做资产配置,斯皮尔曼是必选项。它帮我避免了很多「看起来不相关、实际上很相关」的坑。

总结一下:皮尔逊和斯皮尔曼不是谁替代谁的关系,而是互补。我建议你两个都算,差异大的地方,就是值得深挖的地方。
斯皮尔曼秩相关系数:核心逻辑 原始数据(X, Y) 排名转换 rank(X), rank(Y) 计算排名间的 皮尔逊系数 斯皮尔曼系数 关键特性 • 只关心排序,不关心具体数值 • 对异常值不敏感(排名机制天然抗噪) • 适用于单调关系(线性或非线性) • 无正态分布假设,适用范围更广

这张图把斯皮尔曼的计算流程画得很清楚了。你记住一句话就行:先排名,再算皮尔逊。就这么简单。


公众号:蓝海资料掘金营,微信deep3321