原始因子处理之手写去极值函数

一、去极值

  1. 百分位去极值:直接以上下百分位为边界,将边界外数据归为边界上数据,目前行业内一般不使用。
  2. 标准化去极值:又称为标准差法。标准差本身可以体现因子的离散程度,是基于因子的平均值 Xmean而定的。在离群值处理过程中,可通过用 Xmean±nσ来衡量因子与平均值的距离。 标准差法处理的逻辑与MAD法类似,首先计算出因子的平均值与标准差,其次确认参数 n(这里选定 n = 3,3个标准差以内概率为99.73%),从而确认因子值的合理范围为 [Xmean−nσ,Xmean nσ]
  3. MAD中位数去极值:由于常见的3σ去极值法是基于样本服从正态分布这个假设的,但往往我们发现大部分因子值的分布都并不服从正态分布,厚尾分布的情况较为普遍。因此我们采用更加稳健的MAD(Median Absolute Deviation 绝对中位数法)首先计算因子值的中位数𝑀𝑒𝑑𝑖𝑎𝑛𝑓,并定义绝对中位值为:采取与3σ法等价的方法,我们将大于𝑀𝑒𝑑𝑖𝑎𝑛𝑓 + 3 ∗ 𝑀𝐴𝐷的值或小于𝑀𝑒𝑑𝑖𝑎𝑛𝑓 − 3 ∗ 𝑀𝐴𝐷的值定义为异常值。在对异常值做处理时,需要根据因子的具体情况来决定是直接剔除异常值,还是将异常值设为上下限的数值,常用的方法是后者。 操作步骤:
  • Step1.找出所有因子的中位数median
  • Step2.计算所有因子与1中的median的差值绝对值的中位数MAD
  • Step3.确定边界[median−nMAD,median+nMAD]            

4、相关代码(MAD中位数去极值

def winsorize_med(data, scale=1, inclusive=True, inf2nan=True, axis=1):
    '''
    参数
    ------------
    data: pd.Series/pd.DataFrame, 待缩尾的序列
    scale: 倍数,默认为 1.0。会将位于 [med - scale * distance, med + scale * distance] 边界之外的值替换为边界值/np.nan
    inclusive bool 是否将位于边界之外的值替换为边界值,默认为 True。 如果为 True,则将边界之外的值替换为边界值,否则则替换为 np.nan
    inf2nan: 是否将 np.inf 和 -np.inf 替换成 np.nan,默认为 True。如果为 True,在缩尾之前会先将 np.inf 和 -np.inf 替换成 np.nan,缩尾的时候不会考虑 np.nan,否则 inf 被认为是在上界之上,-inf 被认为在下界之下
    axis: 在 data 为 pd.DataFrame 时使用,沿哪个方向做标准化,默认为 1。0 为对每列做缩尾,1 为对每行做缩尾

    返回
    ------------
    中位数去极值之后的因子数据
    '''
    if isinstance(data,pd.DataFrame):
        value = data.copy()        
        if axis==1:
            long = value.shape[0]
            for i in range(long):
                s = value.iloc[i,:]
                if inf2nan==True:
                    s[np.isinf(s)]=np.nan
                    med = np.median(s.dropna())
                    distance = np.median(np.abs(s-med).dropna())
                    up = med+scale*distance
                    down = med-scale*distance            
                    if inclusive==True:
                        s[s>up]=up
                        s[s<down]=down
                    else:
                        s[s>up]=np.nan
                        s[s<down]=np.nan            
                else:
                    med = np.median(s.dropna())
                    distance = np.median(np.abs(s-med).dropna())
                    up = med+scale*distance
                    down = med-scale*distance
                    if inclusive==True:
                        s[s>up]=up
                        s[s<down]=down
                    else:
                        s[s>up]=np.nan
                        s[s<down]=np.nan
            return value
        elif axis==0:
            width = value.shape[1]
            for j in range(width):
                s = value.iloc[:,j]
                if inf2nan==True:
                    s[np.isinf(s)]=np.nan
                    med = np.median(s.dropna())
                    distance = np.median(np.abs(s-med).dropna())
                    up = med+scale*distance
                    down = med-scale*distance            
                    if inclusive==True:
                        s[s>up]=up
                        s[s<down]=down
                    else:
                        s[s>up]=np.nan
                        s[s<down]=np.nan                
                else:
                    med = np.median(s.dropna())
                    distance = np.median(np.abs(s-med).dropna())
                    up = med+scale*distance
                    down = med-scale*distance
                    if inclusive==True:
                        s[s>up]=up
                        s[s<down]=down
                    else:
                        s[s>up]=np.nan
                        s[s<down]=np.nan
            return value
        else:
            return('axis值有误')
    elif isinstance(data,pd.Series):
        value = data.copy()
        if inf2nan==True:
            value[np.isinf(value)]=np.nan
            med = np.median(value.dropna())
            distance = np.median(np.abs(value-med).dropna())
            up = med+scale*distance
            down = med-scale*distance            
            if inclusive==True:
                value[value>up]=up
                value[value<down]=down
            else:
                value[value>up]=np.nan
                value[value<down]=np.nan  
            return value
        else:
            med = np.median(value.dropna())
            distance = np.median(np.abs(value-med).dropna())
            up = med+scale*distance
            down = med-scale*distance
            if inclusive==True:
                value[value>up]=up
                value[value<down]=down
            else:
                value[value>up]=np.nan
                value[value<down]=np.nan  
            return value
    else:
        print('不是pd.Series和pd.DataFrame类型')
        return

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值