欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-13 15:18:29
...

一、去极值

  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

 

相关标签: 多因子系列