一、去极值
1. MAD
MAD(mean absolute deviation)又称为绝对值差中位数法,是一种先需计算所有因子与平均值之间的距离总和来检测离群值的方法.
def extreme_MAD(rawdata, n):
median = rawdata.quantile(0.5) # 找出中位数
new_median = (abs((rawdata - median)).quantile(0.5)) # 偏差值的中位数
dt_up = median + n * new_median # 上限
dt_down = median - n * new_median # 下限
return rawdata.clip(dt_down, dt_up, axis=1) # 超出上下限的值,赋值为上下限
data7 = filter_extreme_MAD(data6.T,7).T
print(data7)
注:根据dataframe的数据格式,看是否倒置后运算
2. 3σ
3σ法又称为标准差法。标准差本身可以体现因子的离散程度,是基于因子的平均值 Xmean而定的。
def extreme_3sigma(rawdata):
dt_up = rawdata.mean() + 3 * rawdata.std()
dt_down = rawdata.mean() - 3 * rawdata.std()
rawdata = rawdata.clip(dt_down, dt_up, axis=1)
return rawdata
data8 = extreme_3sigma(data6.T).T
print(data8)
注:根据dataframe的数据格式,看是否倒置后运算
3. 百分位法
将因子值进行升序的排序,对排位百分位高于97.5%或排位百分位低于2.5%的因子值,进行类似于 MAD 、 3σ 的方法进行调整。
def filter_extreme_percentile(series,min = 0.10,max = 0.90): #百分位法
series = series.sort_values()
q = series.quantile([min,max])
return np.clip(series,q.iloc[0],q.iloc[1])
def extreme_percentile(rawdata, min=0.025, max=0.975):
p = rawdata.quantile([min, max]) # 得到上下限的值
return rawdata.clip(p.loc[min, :], p.loc[max, :], axis=1)
注:根据dataframe的数据格式,看是否倒置后运算
二、标准化
- 离差标准化(也称线性归一化)
d = (t - t.min( )) / (t.max() - t.min())
注:根据dataframe的数据格式, 看是否倒置后运算
2. 标准差标准化
d = (t - t.mean())/t.std()
注:根据dataframe的数据格式, 看是否倒置后运算
三、正交化
传统方法的缺陷是:如果因子间存在较强的相关性,通过上述加权方式,最终会导致因子对于某种风格的因子重复暴露。使得整个组合的表现严重偏向于该因子,削弱其他因子的效果。
正交化目的是消除因子间的相关性,并保持因子对于收益的解释度不变。
首先进行标准化,使其在同一量纲上可比。
def orth(x):
M = (x.shape[0] - 1) * np.cov(x.T.astype(float)) # 矩阵
D, U = np.linalg.eig(M) # 获取特征值和特征向量
U = np.mat(U) # 转换为np中的矩阵
d = np.mat(np.diag(D ** (-0.5))) # 对特征根元素开(-0.5)指数
S = U * d * U.T # 获取过渡矩阵S
factors_orthogonal_mat = np.mat(x) * S # 获取对称正交矩阵
x = pd.DataFrame(factors_orthogonal_mat, columns=x.columns, index=x.index)
return x
使用截面数据,使用完后检验其相关性是否变小
rawdata.corr()
orth(x).corr()
四、中性化
传统方法的缺陷是对于因子暴露在不同行业、市值上的分布不均匀,比如在小市值医药股上数值偏高,其他偏低,导致可比性下降。
如果是基本面分析需要针对不同的行业进行对比,而中性化直接通过回归取残差来避免类似问题。
中性化的方式是对因子暴露值和市值、行业做线性回归,最后用剩下的残差替代因子值。这个残差肯定是跟市值和行业无关的。
(1)为股票池添加上行业标记,0、1标记
dummy = pd.read_csv('industry_dummy.csv', index_col=0)
import numpy as np
import pandas as pd
import math
from statsmodels import regression
import statsmodels.api as sm
#factor: 以code为index, 因子值为value的series
y = factors
#市值中性化
#mkt_ca: 以股票为index, 市值为value的series
x = mkt_cap.apply(lambda x:math.log(x))
#行业中性化
x = dummy
result = sm.OLS(y.astype(float),x.astype(float)).fit()
output = result.resid