ファイナンス機械学習:特徴量の重要度 特徴量の直交化
特徴量同士に相関関係があると、代替効果によって、MDIやMDA推定で重要度が下げられる傾向がある。
特徴量の次元削減で用いたPCAを用い、特徴量の直交化により、特徴量の線形関係が消滅すれば、代替効果のない特徴量の重要度解析が可能になる
定常な特徴量行列を$${X_{t,n}}$$を考える、ここで、時間のバーと特徴量数について$${t=1,\dots,T, n=1,\dots.N}$$とする。
直交化の前に、この行列を、各特徴量の時間(T)平均値$${\mu_n}$$と分散$${\sigma_n}$$を使い標準化する。
$${Z_{t,n}=\displaystyle{\frac{X_{t,n}-\mu_nu}{\sigma_n}}}$$
この作業によって、特徴量の分散に左右されず、また平均値で中心化することにより特徴量の主方向が明確になる。
固有値分解により、$${{\bf Z}}$$の対角化は
$${{\bf Z}^{T}\{bf ZW}=W\varLambda}$$
なる、固有ベクトル行列$${{\bf W}}$$と固有値を対角に並べた$${{\bf \varLambda}}$$で、$${{\bf P}={\bf ZW}}$$で与えられる。
この対角化の実装はスニペット8.5で与えられている。
ここで、分散閾値を95%と与え、これで与えられる直交特徴量に制限している。
def get_eVec(dot,varThres):
# compute eVec from dot proc matrix, reduce dimension
eVal,eVec=np.linalg.eigh(dot)
idx=eVal.argsort()[::-1] # arugments for sorting eVal desc.
eVal,eVec=eVal[idx],eVec[:,idx]
#2) only positive eVals
eVal=(pd.Series(eVal,index=['PC_'+str(i+1)
for i in range(eVal.shape[0])]))
eVec=(pd.DataFrame(eVec,index=dot.index,columns=eVal.index))
eVec=eVec.loc[:,eVal.index]
#3) reduce dimension, form PCs
cumVar=eVal.cumsum()/eVal.sum()
dim=cumVar.values.searchsorted(varThres)
eVal,eVec=eVal.iloc[:dim+1],eVec.iloc[:,:dim+1]
return eVal,eVec
def getOrthoFeats(dfx,varThres=0.95):
# given a DataFrame, dfx, of features, compute orthofeatures dfP
dfZ=dfx.sub(dfx.mean(),axis=1).div(dfx.std(),axis=1) # standardize
dot=(pd.DataFrame(np.dot(dfZ.T,dfZ),
index=dfx.columns,
columns=dfx.columns))
eVal,eVec=get_eVec(dot,varThres)
dfP=np.dot(dfZ,eVec)
return pd.DataFrame(dfP).add_prefix("ORT_")
この作業により、小さい固有値を持つ特徴量は省略され、特徴量次元は削減される。新しい特徴量次元は、元々に与えられている特徴量とは異なり、PCA重要度解析によるランク付は固有値の値によるランク付けで、教師有り学習のMDI、MDA,SFIとは違い、教師無し学習による結果である。
この直交した特徴量に適用したMDI,MDA,SFI解析によって得られた重要度の順位付けと、PCA順位付けのケンドールの荷重$${\tau}$$を計算することで、この二つの順位付けの一貫性を判定することができる。
ここで、荷重$${\tau}$$とするのは、最も重要な特徴量を重要視しているからである。
ケンドールの荷重$${\tau}$$の計算は、scikit-learnのコードを使う(スニペット8.6)
from scipy.stats import weightedtau
featImp=np.array([0.55,0.33,0.07,0.05]) # feature importance
pcRank=np.array([1,2,3,4],dtype=np.float64) # PCA rank
weightedtau(featImp,pcRank**-1)[0]