首页 文章

检测并排除Pandas数据帧中的异常值

提问于
浏览
104

我有一个包含很少列的pandas数据帧 .

现在我知道某些行是基于某个列值的异常值 .

例如列 - 'Vol'的所有值都在12.xx附近,一个值为4000

现在我想排除那些有Vol Column的行 .

所以基本上我需要设置一个过滤器,以便我们选择所有行,而某个列的值与平均值相差3个标准偏差 .

什么是实现这一目标的优雅方式 .

13 回答

  • 0

    如果你喜欢方法链接,你可以获得所有数字列的布尔条件,如下所示:

    df.sub(df.mean()).div(df.std()).abs().lt(3)
    

    每列的每个值将根据其是否小于三个标准差而转换为 True/False .

  • 0

    删除和删除异常值我认为统计上是错误的 . 它使数据与原始数据不同 . 还使数据的形状不均匀,因此最好的方法是通过对数据进行对数转换来减少或避免异常值的影响 . 这对我有用:

    np.log(data.iloc[:, :])
    
  • 21

    另一种选择是转换数据,以减轻异常值的影响 . 您可以通过winsorizing您的数据来做到这一点 .

    import pandas as pd
    from scipy.stats import mstats
    %matplotlib inline
    
    test_data = pd.Series(range(30))
    test_data.plot()
    

    Original data

    # Truncate values to the 5th and 95th percentiles
    transformed_test_data = pd.Series(mstats.winsorize(test_data, limits=[0.05, 0.05])) 
    transformed_test_data.plot()
    

    Winsorized data

  • 102

    我放弃异常值的功能

    def drop_outliers(df, field_name):
        distance = 1.5 * (np.percentile(df[field_name], 75) - np.percentile(df[field_name], 25))
        df.drop(df[df[field_name] > distance + np.percentile(df[field_name], 75)].index, inplace=True)
        df.drop(df[df[field_name] < np.percentile(df[field_name], 25) - distance].index, inplace=True)
    
  • 1
    #------------------------------------------------------------------------------
    # accept a dataframe, remove outliers, return cleaned data in a new dataframe
    # see http://www.itl.nist.gov/div898/handbook/prc/section1/prc16.htm
    #------------------------------------------------------------------------------
    def remove_outlier(df_in, col_name):
        q1 = df_in[col_name].quantile(0.25)
        q3 = df_in[col_name].quantile(0.75)
        iqr = q3-q1 #Interquartile range
        fence_low  = q1-1.5*iqr
        fence_high = q3+1.5*iqr
        df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)]
        return df_out
    
  • 10

    我喜欢剪辑而不是放弃 . 以下内容将在第2和第98位移动到位 .

    df_list = list(df)
    minPercentile = 0.02
    maxPercentile = 0.98
    
    for _ in range(numCols):
        df[df_list[_]] = df[df_list[_]].clip((df[df_list[_]].quantile(minPercentile)),(df[df_list[_]].quantile(maxPercentile)))
    
  • 0

    像在 numpy.array 中一样使用 boolean 索引

    df = pd.DataFrame({'Data':np.random.normal(size=200)})
    # example dataset of normally distributed data. 
    
    df[np.abs(df.Data-df.Data.mean()) <= (3*df.Data.std())]
    # keep only the ones that are within +3 to -3 standard deviations in the column 'Data'.
    
    df[~(np.abs(df.Data-df.Data.mean()) > (3*df.Data.std()))]
    # or if you prefer the other way around
    

    对于一个系列,它是相似的:

    S = pd.Series(np.random.normal(size=200))
    S[~((S-S.mean()).abs() > 3*S.std())]
    
  • 95

    scipy.stats 有方法 trim1()trimboth() 根据排名和引入的删除值百分比将单行中的异常值删除 .

  • 1

    由于我处于数据科学之旅的早期阶段,我正在使用下面的代码处理异常值 .

    #Outlier Treatment
    
    def outlier_detect(df):
        for i in df.describe().columns:
            Q1=df.describe().at['25%',i]
            Q3=df.describe().at['75%',i]
            IQR=Q3 - Q1
            LTV=Q1 - 1.5 * IQR
            UTV=Q3 + 1.5 * IQR
            x=np.array(df[i])
            p=[]
            for j in x:
                if j < LTV or j>UTV:
                    p.append(df[i].median())
                else:
                    p.append(j)
            df[i]=p
        return df
    
  • 5

    对于每个dataframe列,您可以获得分位数:

    q = df["col"].quantile(0.99)
    

    然后过滤:

    df[df["col"] < q]
    
  • -1

    以下是数据和2组的完整示例:

    进口:

    from StringIO import StringIO
    import pandas as pd
    #pandas config
    pd.set_option('display.max_rows', 20)
    

    包含2组的数据示例:G1:第1组.G2:第2组:

    TESTDATA = StringIO("""G1;G2;Value
    1;A;1.6
    1;A;5.1
    1;A;7.1
    1;A;8.1
    
    1;B;21.1
    1;B;22.1
    1;B;24.1
    1;B;30.6
    
    2;A;40.6
    2;A;51.1
    2;A;52.1
    2;A;60.6
    
    2;B;80.1
    2;B;70.6
    2;B;90.6
    2;B;85.1
    """)
    

    将文本数据读取到pandas数据帧:

    df = pd.read_csv(TESTDATA, sep=";")
    

    使用标准偏差定义异常值

    stds = 1.0
    outliers = df[['G1', 'G2', 'Value']].groupby(['G1','G2']).transform(
               lambda group: (group - group.mean()).abs().div(group.std())) > stds
    

    定义过滤后的数据值和异常值:

    dfv = df[outliers.Value == False]
    dfo = df[outliers.Value == True]
    

    打印结果:

    print '\n'*5, 'All values with decimal 1 are non-outliers. In the other hand, all values with 6 in the decimal are.'
    print '\nDef DATA:\n%s\n\nFiltred Values with %s stds:\n%s\n\nOutliers:\n%s' %(df, stds, dfv, dfo)
    
  • 42

    此答案类似于@tanemaki提供的答案,但使用 lambda 表达式而不是 scipy stats .

    df = pd.DataFrame(np.random.randn(100, 3), columns=list('ABC'))
    
    df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() < 3).all(axis=1)]
    

    要过滤DataFrame,其中只有一列(例如'B')在三个标准差内:

    df[((df.B - df.B.mean()) / df.B.std()).abs() < 3]
    
  • 0

    如果数据框中有多个列,并且想要删除至少有一列中具有异常值的所有行,则以下表达式将一次性执行此操作 .

    df = pd.DataFrame(np.random.randn(100, 3))
    
    from scipy import stats
    df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]
    

相关问题