如何从收益DataFrame滚动计算逆协方差矩阵及报错解决
报错本质原因
- 运行
np.linalg.inv(excess_return.rolling(750).cov().shift())报维度不匹配错误,核心是:pandas的rolling.cov()返回的是双层行索引的长表,行索引第一层为日期、第二层为10个组合名称,整体是二维扁平结构,并不是按日期拆分的三维矩阵结构。直接传入求逆函数时,numpy识别到的最后两个维度不是方阵,自然报错。 - 运行
excess_return.rolling(750).np.linalg.inv(cov()).shift()报属性错误,核心是:pandas的Rolling滚动对象没有内置numpy方法的挂载,这种写法完全不符合API调用规则,Rolling类本身不存在np属性,自然抛出属性不存在的报错。
可落地的实现代码
按照以下步骤即可实现逐交易日生成对应10×10逆协方差矩阵的需求,同时保留原代码里shift(1)的逻辑(确保计算时不使用当日收益,避免前视偏差):
- 计算带偏移的滚动协方差
import numpy as np import pandas as pd # 750天滚动协方差计算完成后整体下移1天,每个日期的协方差仅用该日期之前的收益计算 rolling_cov = excess_return.rolling(window=750).cov().shift(1) - 把长格式的协方差表转换为三维矩阵结构
# 按日期分组,将每个日期下的10行协方差数据重排为独立的10×10矩阵 cov_mat_stack = rolling_cov.groupby(level=0).apply( lambda df: df.values.reshape(10, 10) ).values - 批量求逆
# numpy的linalg.inv原生支持批量处理「样本数×方阵边长×方阵边长」的三维数组 inv_cov_mat_stack = np.linalg.inv(cov_mat_stack) - 给逆矩阵结果绑定日期索引,方便后续调用
rolling_cov_inv = pd.Series( [inv_cov_mat_stack[i] for i in range(len(inv_cov_mat_stack))], index=rolling_cov.index.get_level_values(0).unique() )
常见问题提示
- 序列最开始的749个交易日因为滚动窗口长度不足750天,对应的协方差、逆协方差结果为NaN,属于正常计算结果
- 如果运行中触发
Singular matrix报错,说明对应窗口下的协方差矩阵因为组合收益完全线性相关出现奇异,可先给协方差矩阵的对角线加微小的正则项(如cov_mat_stack += np.eye(10) * 1e-8)再求逆,规避数值计算的奇异问题 - 针对1万多条数据的量级,上述代码的运行效率完全可以满足需求,不需要额外做过度优化
内容的提问来源于stack exchange,提问作者Bjarne Timm
相关产品推荐
相关产品推荐

