根据多列条件过滤熊猫数据框行

时间:2020-09-26 12:49:02

标签: python-3.x pandas dataframe

import pandas as pd

data = {'side':['a', 'a', 'a', 'b', 'a', 'a', 'a', 'b', 'b', 'a'],
        'price':[10400, 10400, 10400, 10380, 1041, 10400, 1041, 10400, 10399, 10399],
        'b_d100_v':[1, 1, 1, 0.3, 10, 10, 10, 10, 9, 9],
        'b_d100_p':[10390, 10391, 10390, 10390, 10390.5, 10385, 10385, 10386, 10387, 10387],
        'a_d052_v':[11, 11, 11, 9.3, 0.1, 0.1, 0.1, 0.1, 0.2, 0.3],
        'a_d052_p':[10399, 10403, 10400, 10401, 1041, 1041, 10400, 10400, 10402, 10404]
        }
df = pd.DataFrame(data, index=[101, 102, 102, 104, 105, 106, 107, 107, 107, 107])

print(df)
    side  price  b_d100_v  b_d100_p  a_d052_v  a_d052_p
101    a  10400       1.0   10390.0      11.0     10399
102    a  10400       1.0   10391.0      11.0     10403
102    a  10400       1.0   10390.0      11.0     10400
104    b  10380       0.3   10390.0       9.3     10401
105    a   1041      10.0   10390.5       0.1      1041  # Row to delete (outlier 1041 on 'price' and 'a_d052_p' columns)
106    a  10400      10.0   10385.0       0.1      1041  # Row to delete (outlier 1041 on 'a_d052_p' column)
107    a   1041      10.0   10385.0       0.1     10400  # Row to delete (outlier 1041 on 'price' column)
107    b  10400      10.0   10386.0       0.1     10400
107    b  10399       9.0   10387.0       0.2     10402
107    a  10399       9.0   10387.0       0.3     10404

我要删除仅在“价格”,“ b_d100_p”和“ a_d052_p”列上包含异常值的行。 为此,我选择使用基于标准偏差的条件。这是我尝试的代码。

row_with_potential_outliers = ['price', 'b_d100_p', 'a_d052_p']
df = df[abs((df[row_with_potential_outliers] - df[row_with_potential_outliers].mean()) / df[row_with_potential_outliers].std()) < 1.5]  # The value '1.5' here is arbitrary, and does not matter too much

print(df)
    side    price  b_d100_v  b_d100_p  a_d052_v  a_d052_p
101  NaN  10400.0       NaN   10390.0       NaN   10399.0
102  NaN  10400.0       NaN   10391.0       NaN   10403.0
102  NaN  10400.0       NaN   10390.0       NaN   10400.0
104  NaN  10380.0       NaN   10390.0       NaN   10401.0
105  NaN      NaN       NaN   10390.5       NaN       NaN  # Row to delete (outlier 1041 on 'price' and 'a_d052_p' columns)
106  NaN  10400.0       NaN   10385.0       NaN       NaN  # Row to delete (outlier 1041 on 'a_d052_p' column)
107  NaN      NaN       NaN   10385.0       NaN   10400.0  # Row to delete (outlier 1041 on 'price' column)
107  NaN  10400.0       NaN   10386.0       NaN   10400.0
107  NaN  10399.0       NaN   10387.0       NaN   10402.0
107  NaN  10399.0       NaN   10387.0       NaN   10404.0

如何保留列“ side”,“ b_d100_v”和“ a_d052_v”的原始值?这将允许我然后应用'dropna()'来实现目标……也许还有更好的解决方案? 我使用具有数百列和数千行的数据框,因此出于性能原因,我想尽可能避免迭代。 预先感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

首先,要使用专有名称,请使用以下命令设置列表名称 列进行检查,就像 cols_to_check

cols_to_check = ['price', 'b_d100_p', 'a_d052_p']

请注意,尚未找到具有异常值的。 您仅指定哪些列来检查异常值。

然后定义一个函数来查找异常值 列,并具有指定的阈值:

def isOutlier(col, thr):
    return ((col - col.mean()) / col.std()).abs() > thr

要删除带有异常值的行,请运行:

df = df[~df[cols_to_check].apply(isOutlier, thr=1.5).any(axis=1)]

结果是:

    side  price  b_d100_v  b_d100_p  a_d052_v  a_d052_p
101    a  10400       1.0   10390.0      11.0     10399
102    a  10400       1.0   10391.0      11.0     10403
102    a  10400       1.0   10390.0      11.0     10400
104    b  10380       0.3   10390.0       9.3     10401
107    b  10400      10.0   10386.0       0.1     10400
107    b  10399       9.0   10387.0       0.2     10402
107    a  10399       9.0   10387.0       0.3     10404

要完全理解该代码的工作方式,

  1. 要查看检查是否有任何元素是完整元素的完整结果 离群值,在其列中,运行:

     df[cols_to_check].apply(isOutlier, thr=1.5)
    

    您将 isOutlier 函数应用于 cols_to_check 列表中的每一列, 通过所选的阈值。结果是:

          price  b_d100_p  a_d052_p
     101  False     False     False
     102  False     False     False
     102  False     False     False
     104  False     False     False
     105   True     False      True
     106  False     False      True
     107   True     False     False
     107  False     False     False
     107  False     False     False
     107  False     False     False
    
  2. 获取每一行的累积结果(是否为 any 元素 连续 True ),运行:

     df[cols_to_check].apply(isOutlier, thr=1.5).any(axis=1)
    

    结果是:

     101    False
     102    False
     102    False
     104    False
     105     True
     106     True
     107     True
     107    False
     107    False
     107    False
     dtype: bool
    

因此,如果您运行df[~...],则会在上述情况下获得行 是 False ,并且仅将此结果保存回 df 中。

请注意,您要删除包含至少一个异常值的行, 不要将异常值更改为 NaN (因为这是代码的结果)。

答案 1 :(得分:1)

要使您的方法提供所需的输出,您只需要将异常值移除应用于数据框df的指定列

df[row_with_potential_outliers] = df[row_with_potential_outliers][abs((df[row_with_potential_outliers] - df[row_with_potential_outliers].mean()) / df[row_with_potential_outliers].std()) < 1.5]

    side    price  b_d100_v  b_d100_p  a_d052_v  a_d052_p
101    a  10400.0       1.0   10390.0      11.0   10399.0
102    a  10400.0       1.0   10391.0      11.0   10403.0
102    a  10400.0       1.0   10390.0      11.0   10400.0
104    b  10380.0       0.3   10390.0       9.3   10401.0
105    a      NaN      10.0   10390.5       0.1       NaN
106    a  10400.0      10.0   10385.0       0.1       NaN
107    a      NaN      10.0   10385.0       0.1   10400.0
107    b  10400.0      10.0   10386.0       0.1   10400.0
107    b  10399.0       9.0   10387.0       0.2   10402.0
107    a  10399.0       9.0   10387.0       0.3   10404.0