代码之家  ›  专栏  ›  技术社区  ›  Cesar

使用group by之前筛选异常值

  •  0
  • Cesar  · 技术社区  · 6 年前

    我有一个带有价格列(P)的数据框架,我有一些不需要的值,比如(0,1.50,92.80,0.80)。在按产品代码计算价格平均值之前,我想删除这些异常值

                    Code    Year    Month  Day   Q      P
    0               100     2017       1    4   2.0  42.90
    1               100     2017       1    9   2.0  42.90
    2               100     2017       1   18   1.0  45.05
    3               100     2017       1   19   2.0  45.05
    4               100     2017       1   20   1.0  45.05
    5               100     2017       1   24  10.0  46.40
    6               100     2017       1   26   1.0  46.40
    7               100     2017       1   28   2.0  92.80
    8               100     2017       2    1   0.0   0.00
    9               100     2017       2    7   2.0   1.50
    10              100     2017       2    8   5.0   0.80
    11              100     2017       2    9   1.0  45.05
    12              100     2017       2   11   1.0   1.50
    13              100     2017       3    8   1.0  49.90
    14              100     2017       3   17   6.0  45.05
    15              100     2017       3   24   1.0  45.05
    16              100     2017       3   30   2.0   1.50
    

    如何过滤每个产品的异常值(按代码分组)?

    我试过这个:

    stds = 1.0  # Number of standard deviation that defines 'outlier'.
    z = df[['Code','P']].groupby('Code').transform(
        lambda group: (group - group.mean()).div(group.std()))
    outliers = z.abs() > stds
    df[outliers.any(axis=1)]
    

    然后:

    print(df[['Code', 'Year', 'Month','P']].groupby(['Code', 'Year', 'Month']).mean())
    

    但是离群值过滤器不能正常工作。

    2 回复  |  直到 6 年前
        1
  •  2
  •   sacuL    6 年前

    IIUC您可以在上使用GroupBy Code 做你的 z 分数计算 P ,并过滤 Z 分数大于您的阈值:

    stds = 1.0 
    filtered_ df = df[~df.groupby('Code')['P'].transform(lambda x: abs((x-x.mean()) / x.std()) > stds)]
    
        Code  Year  Month  Day     Q      P
    0    100  2017      1    4   2.0  42.90
    1    100  2017      1    9   2.0  42.90
    2    100  2017      1   18   1.0  45.05
    3    100  2017      1   19   2.0  45.05
    4    100  2017      1   20   1.0  45.05
    5    100  2017      1   24  10.0  46.40
    6    100  2017      1   26   1.0  46.40
    11   100  2017      2    9   1.0  45.05
    13   100  2017      3    8   1.0  49.90
    14   100  2017      3   17   6.0  45.05
    15   100  2017      3   24   1.0  45.05
    
    filtered_df[['Code', 'Year', 'Month','P']].groupby(['Code', 'Year', 'Month']).mean()
                         P
    Code Year Month           
    100  2017 1      44.821429
              2      45.050000
              3      46.666667
    
        2
  •  1
  •   jpp    6 年前

    你的想法是对的。只需取与你相反的布尔值 outliers['P'] 系列通孔 ~ 并通过过滤数据帧 loc :

    res = df.loc[~outliers['P']]\
            .groupby(['Code', 'Year', 'Month'], as_index=False)['P'].mean()
    
    print(res)
    
       Code  Year  Month          P
    0   100  2017      1  44.821429
    1   100  2017      2  45.050000
    2   100  2017      3  46.666667