python - Pandas Groupby 过滤器从每个组中删除异常值
问题描述
我有一个 Pandas DataFrame,其中包含 3 个分类分组变量和 1 个数值结果变量。在每个组内,有一个 n = 6,其中一个值可能是异常值(由每个组内的分布定义:异常值可以超过四分位数 3 的四分位数间距的 1.5 倍,或者小于四分位数 1 乘以四分位数间距的 1.5 倍)。
DataFrame 的示例如下所示:
# Making the df without our outcome variable
import numpy as np
import pandas as pd
G1 = np.repeat(['E', 'F'], 24)
G2 = np.tile(np.repeat(['C', 'D'], 6), 4)
G3 = np.tile(np.repeat(['A', 'B'], 12), 2)
dummy_data = pd.DataFrame({'G1' : G1, 'G2' : G2, 'G3': G3})
# Defining a function to generate a numpy array with n = 6, where one of these values is an outlier # by our previous definition
np.random.seed(0)
def outlier_arr(low, high):
norm_arr = np.random.randint(low, high, 5)
IQR = np.percentile(norm_arr, 75) - np.percentile(norm_arr, 25)
upper_fence = np.percentile(norm_arr, 75) + (IQR * 1.5)
lower_fence = np.percentile(norm_arr, 25) - (IQR * 1.5)
rand_decision = np.random.randint(0, 2, 1)[0]
if rand_decision == 1:
high_outlier = np.round(upper_fence * 3, decimals = 0)
final_arr = np.hstack([norm_arr, high_outlier])
else:
low_outlier = np.round(lower_fence * (1/3), decimals = 0)
final_arr = np.hstack([norm_arr, low_outlier])
return final_arr.astype(int)
# Making a list to add into the dataframe to represent our values
abund_arr = []
for i in range(0, 8):
abund_arr = abund_arr + outlier_arr(700, 800).tolist()
abund_arr = np.array(abund_arr)
# Appending this list as a new row
dummy_data['V1'] = abund_arr
这应该生成一个包含 3 个分组变量G1
、G2
和G3
以及一个结果变量的 DataFrame,V1
其中每个组都应该有一个需要删除的异常值。我们可以查看下面的前 6 行(单个组),dummy_data.head(6)
看看其中一个值(最后一行)是我们想要过滤掉的异常值。
G1 G2 G3 V1
0 E C A 744
1 E C A 747
2 E C A 764
3 E C A 767
4 E C A 767
5 E C A 2391 <--- outlier
据我了解,一个好的方法可能是使用 df.groupby().filter(),并按变量分组G1
,G2
并G3
实现一个用户定义的函数,filter()
该函数根据上面讨论的异常值标准返回 T/F .
我已经尝试过,其中用于检测数组中异常值(返回True
or数组False
)的函数如下所示:
def is_outlier(x):
IQR = np.percentile(x, 75) - np.percentile(x, 25)
upper_fence = np.percentile(x, 75) + (IQR * 1.5)
lower_fence = np.percentile(x, 25) - (IQR * 1.5)
return (x > upper_fence) | (x < lower_fence)
正确检测到异常值,如下所示:
test_arr = outlier_arr(300, 500)
is_outlier(test_arr)
# returns an array of [False, False, False, False, False, True]
但是,当在 pandas 对象上使用上述方法时,以下代码不会引发错误,但也不会过滤任何异常值:
dummy_data.groupby(['G1', 'G2', 'G3']).filter(lambda x: (is_outlier(x['V1'])).any())
注意:我实际上在这里找到了一种方法,在这里你使用apply()
而不是filter()
.
运行dummy_data[~dummy_data.groupby(['G1', 'G2', 'G3'])['V1'].apply(is_outlier)]
产生了预期的结果。
但是,只是为了使用这种方法,需要进行什么调整才能使其正常工作filter()
?如果可能,这两种方法中哪一种是正确/首选的?
提前致谢。
解决方案
推荐阅读
- java - 原始包装类(整数、双精度等)和字符串可以近似为基于值的类吗?
- asp.net - 为什么我的引导模板在 Asp.net 中不起作用?
- gnuplot - 在 Gnuplot 中更改 x 轴比例
- python-3.x - 拆分数据框中的每一行
- php - PHP如何从字符串中删除单词并添加另一个单词?
- laravel - 如何获取 Auth::user()->email 等数据;用于自定义身份验证表
- php - 如何发布到 Swagger API?
- react-native - 如何在本机反应中将渲染图标放置在 TextInput 顶部
- r - 将我的 ggplot 代码更改为仅显示半场
- java - 有没有办法将当前时间戳实际附加到这个 json 文件上?