滑动计算的几种方法及效率对比——计算滑动相关系数

一、情景描述:

有日收益率矩阵:chg_1d_df(长下面这样)column:code,index:date。对于每一日:

1.计算22日的移动皮尔逊相关系数:(股票i,j  的22日收益率序列)

\rho _{i,j}(\Delta t)=\frac{cov(\overrightarrow{ret_{i}} , \overrightarrow{ret_{j}})}{std(\overrightarrow{ret_{i}})std(\overrightarrow{ret_{j}})}

2.计算每只股票和其他股票相关系数的平均值:

P_{i}=\frac{1}{N-1}\sum_{j\neq i}^{N}\rho _{i,j}(\Delta t)

二、方法:

1.用pandas.rolling()暴力循环codes,再concant

最开始我是这么写的,跑一个486*5155的 df 花了我4h :<

p_1d_df=pd.DataFrame()
for c1 in tqdm(list(stk_aftNAN.keys())):
    p=chg_1d_df[c1].rolling(22).corr(chg_1d_df)    
    p_1d_df=pd.concat([p_1d_df,p.drop(columns=c1).mean(axis=1)],axis=1)
p_1d_df=p_1d_df.replace(np.inf,np.nan).replace(-np.inf,np.nan).dropna(how='all',axis=0)

2. 用pandas.rolling()直接算,不循环,再unstack

不知道会花多久,但是目测应该比1.快一丢丢,毕竟没有循环concat了(这东西很慢我是知道的)。但因为不能用tqdm看进度了,没有耐心跑完hhh :<

corr_df=chg_1d_df.rolling(22).corr()
p_1d_df=((corr_df.sum(axis=1)-1)/(corr_df.shape[1]-1)).unstack()

3.用numpy.lib.stride_stricks.sliding_window_view() ,先list拼接再转array

v=np.lib.stride_tricks.sliding_window_view(chg_1d_df,  (22,chg_1d_df.shape[1]))
p_1d_df=[[np.nan]*chg_1d_df.shape[1]]*21
for vi in v[:,0,:,:]:
    p_1d_df.append((np.corrcoef(vi,rowvar=False).sum(axis=1)-1)/(chg_1d_df.shape[1]-1))
p_1d_df=np.array(p_1d_df)

4.用sliding直接拼array

其实貌似和3.没什么太大的区别,就看list还是array的append谁快了。

但是有na值的时候,处理不了!!!!!

目前我只知道用码掩解决:np.ma.masked_invalid() 和 np.ma.corrcoef()

v=np.lib.stride_tricks.sliding_window_view(chg_1d_df,  (22,chg_1d_df.shape[1]))
v=np.ma.masked_invalid(v)
p_1d_df=np.full((21,chg_1d_df.shape[1]),np.nan)
for vi in v[:,0,:,:]:
    p_1d_df=np.append(p_1d_df, [(np.ma.corrcoef(vi,rowvar=False).sum(axis=1)-1)/(chg_1d_df.shape[1]-1)],axis=0)

1hour后更新:

但是其实算相关系数时不需要处理na,有na就说明这22天内这只股票数据不全,本来就会被剔除,所以算出来直接就是na,不用管。

只需要在sum的时候忽略na值就行了。

but这里要注意!!!

ndarray.sum()是不忽略nan的,有nan结果就直接全部成nan了。而np.nansum()是可以忽略nan的 : )

关于为什么不直接用nanmean(),因为要去除和自己的相关系数1.(但其实,这个时候,股票好几千只,减不减1影响不大...但是还是严谨点 )

s=datetime.now()
v=np.lib.stride_tricks.sliding_window_view(chg_1d_df,  (22,chg_1d_df.shape[1]))
p_1d_df=np.full((21,chg_1d_df.shape[1]),np.nan)
for vi in v[:,0,:,:]:
    corr=np.corrcoef(vi,rowvar=False)
    p_1d_df=np.append(p_1d_df, [(np.nansum(np.corrcoef(vi,rowvar=False),axis=1)-1)/(np.where(corr==np.nan,0,1).sum(axis=1)-1)],axis=0)
scc_df=1/(2*(1-p_1d_df))
scc_df=pd.DataFrame(scc_df,columns=list(stk_aftNAN.keys()),index=chg_1d_df.index)
e=datetime.now()
print("time",e-s)

5.bottleneck

but不知道怎么用bottleneck算滑动相关系数,搜也搜不到 T^T

可是他真的比numpy快好多好多

三.效率对比:

用了个100*500 的数据来跑,对比一下2.3.4的速度:

### 耗时对比 ###
df=pd.DataFrame(np.random.randint(0,100,(100,500)),index=np.arange(1,101),columns=np.arange(1,501))
print('np和pandas耗时对比: 100*500')

##--------------------------view_list转array---------------------##
s=datetime.now()
v=np.lib.stride_tricks.sliding_window_view(df, (20,df.shape[1]))
p_1d_df=[[np.nan]*df.shape[1]]*19
for vi in v[:,0,:,:]:
    p_1d_df.append((np.corrcoef(vi,rowvar=False).sum(axis=1)-1)/(vi.shape[1]-1))
p_1d_df=np.array(p_1d_df)
e=datetime.now()
print("view_list转array",e-s)

##--------------------------view_直接用array---------------------##
s=datetime.now()
v=np.lib.stride_tricks.sliding_window_view(df, (20,df.shape[1]))

p_1d_df=np.full((19,df.shape[1]),np.nan)

for vi in v[:,0,:,:]:
    p_1d_df=np.append(p_1d_df,[ (np.corrcoef(vi,rowvar=False).sum(axis=1)-1)/(vi.shape[1]-1)],axis=0)

e=datetime.now()
print("view_直接用array",e-s)

##----------------------pandas.rolling()-------------------------##
s=datetime.now()
corr_df=df.rolling(20).corr()
p_1d_df=((corr_df.sum(axis=1)-1)/(df.shape[1]-1)).unstack()
e=datetime.now()
print("pandas.rolling()",e-s)

结果:

四.总结&问题:

  1. Bottle>numpy>pandas
  2. 少用循环
  3. numpy对nan很不友好,必须用np.ma带码掩的处理,但是时间会延长很多:<
  • 所以除了这些,还有没有其他快一点的办法?
  • bottle真的不能算相关系数吗?不然难道只能用 cov/std*std ?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值