一、情景描述:
有日收益率矩阵:chg_1d_df(长下面这样)column:code,index:date。对于每一日:
1.计算22日的移动皮尔逊相关系数:(股票i,j 的22日收益率序列)
2.计算每只股票和其他股票相关系数的平均值:
二、方法:
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)
结果:
四.总结&问题:
- Bottle>numpy>pandas
- 少用循环
- numpy对nan很不友好,必须用np.ma带码掩的处理,但是时间会延长很多:<
- 所以除了这些,还有没有其他快一点的办法?
- bottle真的不能算相关系数吗?不然难道只能用 cov/std*std ?