[英]Filtering pandas dataframe rows based on a multiple column condition
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()' 来实现我的目的......或者也许有更好的解决方案? 我使用具有数百列和数千行的数据帧,因此出于性能原因,我希望尽可能避免迭代。 在此先感谢您的帮助。
首先,要使用专有名称,请使用列设置列表名称以检查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
要完全理解此代码的工作原理:
要查看检查任何元素是否为异常值的完整结果,请在其列中运行:
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
要获取每一行的累积结果(无论一行中的任何元素为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 (因为它是您的代码的结果)。
为了使您的方法提供所需的输出,您只需要将异常值去除应用于数据帧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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.