如何将阈值应用于pandas DataFrame列并输出超出阈值的行?

问题描述 投票:4回答:3

我有一个大型的产品系列数据集。我试图捕捉任何价格过高/低于其他家庭成员的奇怪数据条目。例如,我有一个这个pandas.DataFrame

df =
Prices    Product Family
0    1.99        Yoplait
1    1.89        Yoplait
2    1.59        Yoplait
3    1.99        Yoplait
4    7.99        Yoplait
5    12.99       Hunts 
6    12.99       Hunts 
7    2.99        Hunts 
8    12.49       Hunts

我想编写一个for循环,遍历每个Product Family,设置某种阈值来识别哪些产品有问题(第4行和第7行),然后吐出该行。我怎样才能做到这一点?

到目前为止我有这个:

families = df['Product Family'].unique() 
for i in families: 
   if df['Prices] .....(set threshold)
   then.....(spit out that row that is questionable)

然后,我最好在for循环中为每个产品系列完成if语句。有没有人有关于如何设置此阈值并完成代码的想法(或更好的想法)?

python pandas for-loop dataframe threshold
3个回答
3
投票

使用pandas时,最好不要使用循环。在你的情况下,我们可以使用groupby()来做类似家庭的操作。以下是使用与组中位数不同的值来查找异常值的一种方法:

Code:

df['median'] = df.groupby('Product_Family').transform('median')
df['outlier'] = ((df.Prices - df['median']) / df['median']).abs() > 0.5

Test Code:

import pandas as pd

df = pd.read_fwf(StringIO(u"""
    Prices      Product_Family
    1.99        Yoplait
    1.89        Yoplait
    1.59        Yoplait
    1.99        Yoplait
    7.99        Yoplait
    12.99       Hunts 
    12.99       Hunts 
    2.99        Hunts 
    12.49       Hunts"""),
                 skiprows=1)

df['median'] = df.groupby('Product_Family').transform('median')
df['outlier'] = ((df.Prices - df['median']) / df['median']).abs() > 0.5

print(df[df.outlier])    
print(df)

Results:

   Prices Product_Family  median  outlier
4    7.99        Yoplait    1.99     True
7    2.99          Hunts   12.74     True

   Prices Product_Family  median  outlier
0    1.99        Yoplait    1.99    False
1    1.89        Yoplait    1.99    False
2    1.59        Yoplait    1.99    False
3    1.99        Yoplait    1.99    False
4    7.99        Yoplait    1.99     True
5   12.99          Hunts   12.74    False
6   12.99          Hunts   12.74    False
7    2.99          Hunts   12.74     True
8   12.49          Hunts   12.74    False

2
投票

嗯,我想我的方式与Stephen Rauch相似。唯一的区别是我标准化/标准化每组的prices

# Standardize or normalize the `Prices` per `ProductFamily` (absolute value)
df_std = df.groupby('ProductFamily').transform(lambda x: np.abs((x - x.mean()) / x.std()))

# We assume that any Price beyond one standard deviation is an outlier
outlier_mask = df_std['Prices'] > 1.0

# Split clean and outlier dataframes
df_clean = df[~outlier_mask]
df_outlier = df[outlier_mask]

1
投票

如同在其他答案中一样,还可以使用分位数来进行离群检测以及分组和变换。以下使用0.05和0.95分位数作为限制:

# FIND LOWER AND UPPER LIMITS: 
df["lower"] = df.groupby("ProductFamily").transform(lambda x: x.quantile(0.05))
df["upper"] = df.iloc[:,0:2].groupby("ProductFamily").transform(lambda x: x.quantile(0.95))
print(df) 

# SELECT ROWS THAT MEET CRITERIA: 
df = df[(df.Prices > df.lower) & (df.Prices < df.upper)]
print(df)

# TO KEEP ORIGINAL 2 COLUMNS:
df = df.iloc[:,0:2]
print(df)

输出:

   Prices ProductFamily  lower  upper
0    1.99       Yoplait  1.650   6.79
1    1.89       Yoplait  1.650   6.79
2    1.59       Yoplait  1.650   6.79
3    1.99       Yoplait  1.650   6.79
4    7.99       Yoplait  1.650   6.79
5   12.99         Hunts  4.415  12.99
6   12.99         Hunts  4.415  12.99
7    2.99         Hunts  4.415  12.99
8   12.49         Hunts  4.415  12.99

   Prices ProductFamily  lower  upper
0    1.99       Yoplait  1.650   6.79
1    1.89       Yoplait  1.650   6.79
3    1.99       Yoplait  1.650   6.79
8   12.49         Hunts  4.415  12.99

   Prices ProductFamily
0    1.99       Yoplait
1    1.89       Yoplait
3    1.99       Yoplait
8   12.49         Hunts
© www.soinside.com 2019 - 2024. All rights reserved.