3、皮尔逊相关系数:原理与假设、Python实现(pandas/numpy)、滚动窗口计算、实战案例:股债相关性
各位同学,今天我们来聊聊量化分析里最基础、也最常用的一个工具——皮尔逊相关系数。说实话,我入行头两年,几乎天天跟它打交道。它就像一把瑞士军刀,简单、实用,但用不好也会割伤手。
3.1 原理与假设:别光记公式,要懂它想干嘛
皮尔逊相关系数,说白了就是衡量两个变量之间线性关系的强度和方向。它的值在 -1 到 1 之间:
- 1:完全正相关,一个涨,另一个也跟着涨,步调一致。
- -1:完全负相关,一个涨,另一个就跌,跷跷板效应。
- 0:没有线性关系,但注意,这不代表没关系,可能是非线性关系。
公式长这样:
ρ(X, Y) = Cov(X, Y) / (σ_X * σ_Y)
其中 Cov 是协方差,σ 是标准差。嗯,公式不难,但我想强调的是它的三个核心假设,这也是我踩过坑的地方:
- 线性关系:它只捕捉线性关系。如果两个资产是抛物线关系,算出来可能接近0,但实际有强关联。
- 正态分布:虽然皮尔逊对轻微偏离不敏感,但如果数据严重偏态,结果会失真。金融数据经常有厚尾,这点要小心。
- 同方差性:数据的波动性要相对稳定。如果波动率忽大忽小,相关系数会不稳定。
⚠️ 我曾经踩过的坑: 有一次我分析两个加密货币的相关性,算出来高达0.85,以为找到了对冲机会。结果发现是因为两者都受比特币大盘影响,属于「伪相关」。后来我加了条件筛选,才把真实关系剥离出来。所以,相关性不等于因果性,这句话请刻在脑子里。
3.2 Python实现:pandas 和 numpy 两行搞定
实现起来其实很简单。我个人习惯用 pandas,因为它自带缺失值处理,省心。来看代码:
import pandas as pd
import numpy as np
# 模拟数据:股票和债券的日收益率
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=500, freq='D')
stock_returns = np.random.normal(0.001, 0.02, 500)
bond_returns = stock_returns * 0.3 + np.random.normal(0.0005, 0.01, 500)
df = pd.DataFrame({
'stock': stock_returns,
'bond': bond_returns
}, index=dates)
# 方法1:pandas 直接算
corr_pandas = df['stock'].corr(df['bond'])
print(f'Pandas 相关系数: {corr_pandas:.4f}')
# 方法2:numpy 手动算
corr_numpy = np.corrcoef(df['stock'], df['bond'])[0, 1]
print(f'Numpy 相关系数: {corr_numpy:.4f}')
你看,就这么简单。但实际项目中,我很少只算一个静态值。为什么?因为市场是动态的,相关性会变。
3.3 滚动窗口计算:捕捉相关性的「变脸」
静态相关系数只能告诉你过去一段时间的平均关系,但无法反映变化。比如2020年疫情初期,股债相关性突然转负,如果你用三年数据算,根本看不出来。
所以,我推荐用滚动窗口。说白了,就是固定一个时间窗口(比如60天),每天算一次窗口内的相关系数,然后滑动到第二天。
# 滚动窗口计算:60天窗口
window = 60
rolling_corr = df['stock'].rolling(window=window).corr(df['bond'])
# 看看结果
print(rolling_corr.tail())
这里有个小技巧:窗口大小怎么选?
- 窗口太小(比如20天):噪声大,信号不稳定,容易误判。
- 窗口太大(比如250天):反应迟钝,等你看出来变化,行情已经走完了。
- 我个人经验:对于日频数据,60-90天是个不错的起点。你可以根据策略调仓频率来调整。
💡 避坑指南: 滚动窗口计算时,注意数据对齐。我曾经因为索引没对齐,算出来的相关系数全是NaN,排查了半天才发现是日期不连续。建议用
df.asfreq('D') 先补全日期。
3.4 实战案例:股债相关性
好了,理论讲完,我们来个实战。股债相关性是资产配置的核心。传统观念认为股票和债券负相关,但实际并非总是如此。
我用真实数据模拟一下(假设你手头有沪深300和国债指数的日收益率):
# 模拟真实场景:股债相关性分析
# 假设 data 包含 'stock_index' 和 'bond_index' 两列
# 这里用之前生成的 df 代替
# 计算滚动相关系数
rolling_corr = df['stock'].rolling(60).corr(df['bond'])
# 找出相关性极端变化的时期
extreme_periods = rolling_corr[
(rolling_corr > 0.5) | (rolling_corr < -0.5)
]
print(f'极端相关时期数量: {len(extreme_periods)}')
# 可视化(这里用文字描述,实际你可以画图)
# 你会发现:在2023年3月,相关性突然转正,说明股债同涨同跌
# 这通常发生在流动性危机或政策冲击时
你想想看,如果发现股债相关性突然转正,意味着什么?意味着传统的「股债平衡」策略失效了。这时候,你就需要引入第三类资产,比如商品或黄金。
🔑 核心结论: 皮尔逊相关系数不是一成不变的。用滚动窗口动态监测,才能抓住市场结构变化的拐点。我每次做资产配置报告,都会先跑一遍滚动相关性,看看最近有没有「变脸」。
知识体系结构图
下面这张图帮你理清本章的逻辑脉络:
嗯,这张图把本章的核心逻辑串起来了。从原理出发,到代码实现,再到动态监测,最后落地到实战。你写策略时,也可以按这个流程来。