如何将阈值应用于 pandas DataFrame 列并输出超出阈值的行?
How to apply a threshold to a pandas DataFrame column and output a row outside of the threshold?
我有一个很大的产品系列数据集。我正在尝试捕获任何价格比其他家庭成员 high/low 高的奇怪数据条目。例如,我有一个 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 循环,遍历每个产品系列,设置某种阈值来识别哪些产品有问题(第 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 语句。有没有人对如何设置此阈值和完成代码有想法(或更好的想法)?
使用pandas时最好尽可能不要使用循环。在您的情况下,我们可以使用 groupby()
来执行类似家庭的操作。这是使用与组中位数不同的值来查找异常值的一种方法:
代码:
df['median'] = df.groupby('Product_Family').transform('median')
df['outlier'] = ((df.Prices - df['median']) / df['median']).abs() > 0.5
测试代码:
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)
结果:
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
也可以像其他答案一样使用分位数通过分组和转换进行离群值检测。以下使用 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
好吧,我想我的方法与 Stephen Rauch 的方法相似。唯一的区别是我 standardize/normalize 每组 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]
我有一个很大的产品系列数据集。我正在尝试捕获任何价格比其他家庭成员 high/low 高的奇怪数据条目。例如,我有一个 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 循环,遍历每个产品系列,设置某种阈值来识别哪些产品有问题(第 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 语句。有没有人对如何设置此阈值和完成代码有想法(或更好的想法)?
使用pandas时最好尽可能不要使用循环。在您的情况下,我们可以使用 groupby()
来执行类似家庭的操作。这是使用与组中位数不同的值来查找异常值的一种方法:
代码:
df['median'] = df.groupby('Product_Family').transform('median')
df['outlier'] = ((df.Prices - df['median']) / df['median']).abs() > 0.5
测试代码:
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)
结果:
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
也可以像其他答案一样使用分位数通过分组和转换进行离群值检测。以下使用 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
好吧,我想我的方法与 Stephen Rauch 的方法相似。唯一的区别是我 standardize/normalize 每组 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]