我正在寻找一种高效/快速的方法,用多维numpy数组计算几个weithings/投资组合的波动率/标准差
我有一个多维核协方差数组,即形状为260,5,5的cov_3d
对于260个案例中的每一个,我有5个资产的10个权重,即形状为260,10,5的权重
利用numpy-Einstein求和,我可以计算260s10x10协方差,并提取对角矩阵。
因为,我只需要对角矩阵,一个更快、更有效的方式应该存在,这样我就省去了上下矩阵的计算。
import numpy as np
# observations just for covariance matrix
observations_3d = np.random.normal(size=(260,5,200))
#260 covariance matrix for 5 assets
cov_3d = np.einsum('nij,njk->nik', observations_3d, observations_3d.transpose([0,2,1]))/(200-1)
#for each 260 cases, 10 weightings of the 5 assets
weights_3d = np.random.uniform(size=(260,10,5))
print(weights_3d.shape) #260x10x5
print(cov_3d.shape) #260x5x5
#aim: calculate standard deviation/volatility of the 10 weightings/portfolios for each of the 260 cases
#now, its gets ugly
wCovw_3d = np.einsum('nij,njk->nik',weights_3d, np.einsum('nij,njk->nik', cov_3d, weights_3d.transpose([0,2,1])))
print (wCovw_3d.shape) #260x10x10
std_3d = np.diagonal(wCovw_3d,axis1=1,axis2=2)**.5
输出应为v,T=1,…,260和P=1,…,10的元素如上所述
最佳答案
我们可以直接去那里-
std_3d = np.einsum('nij,njl,nil->ni',weights_3d, cov_3d, weights_3d)
导致的进展是-
从-
wCovw_3d = np.einsum('nij,njk->nik',weights_3d, np.einsum('nij,njk->nik', cov_3d, weights_3d.transpose([0,2,1])))
简化转置部分-
wCovw_3d = np.einsum('nij,njk->nik',weights_3d, np.einsum('nij,nkj->nik', cov_3d, weights_3d))
把这个带到一个电话里-
wCovw_3d = np.einsum('nij,njl,nkl->nik',weights_3d, cov_3d, weights_3d)
因为我们对最终输出的对角线很感兴趣,所以我们可以将对角线字符串(i和k)等价,从而得到最终表达式-
std_3d = np.einsum('nij,njl,nil->ni',weights_3d, cov_3d, weights_3d)
别忘了在结尾加上那一部分。
或者,使用
**.5
-p1 = np.matmul(weights_3d,cov_3d)
std_3d_out = np.matmul(p1[...,None,:],weights_3d[...,None])[...,0,0]
在Python 3.x上使用等效的@operator-
((weights_3d@cov_3d)[...,None,:]@weights_3d[...,None])[...,0,0]