在 Python 中查找并用 nan 替换异常值
Find and replace outliers with nan in Python
我开始使用 python 并且我正在尝试使用分位数找出每年的异常值
我的数据组织如下:
年列,每年我都有几个月及其相应的盐度和温度
year=[1997:2021]
month=[1,2...]
SAL=[33,32,50,......,35,...]
以下是我的代码:
#1st quartile
Q1 = DF['SAL'].quantile(0.25)
#3rd quartile
Q3 = DF['SAL'].quantile(0.75)
#calculate IQR
IQR = Q3 - Q1
print(IQR)
df_out = DF['SAL'][((DF['SAL'] < (Q1 - 1.5 * IQR)) |(DF['SAL'] > (Q3 + 1.5 * IQR)))]
我想识别异常值的月份和年份,并用nan替换它。
您可以使用以下功能。它使用低于 Q1-1.5IQR 或高于 Q3+1.5IQR 的离群值定义,例如箱线图的经典定义。
import pandas as pd
import numpy as np
df = pd.DataFrame({'year': np.repeat(range(1997,2022), 12),
'month': np.tile(range(12), 25)+1,
'SAL': np.random.randint(20,40, size=12*25)+np.random.choice([0,-20, 20], size=12*25, p=[0.9,0.05,0.05]),
})
def outliers(s, replace=np.nan):
Q1, Q3 = np.percentile(s, [25 ,75])
IQR = Q3-Q1
return s.where((s > (Q1 - 1.5 * IQR)) & (s < (Q3 + 1.5 * IQR)), replace)
# add new column with excluded outliers
df['SAL_excl'] = df.groupby('year')['SAL'].apply(outliers)
检查它是否有效:
异常值:
import seaborn as sns
sns.boxplot(data=df, x='year', y='SAL')
没有异常值:
sns.boxplot(data=df, x='year', y='SAL_excl')
注意。由于过滤,新的异常值可能会出现,因为数据现在有了新的 Q1/Q3/IQR。
如何检索带有离群值的行:
df[df['SAL_excl'].isna()]
输出:
year month SAL SAL_excl
28 1999 5 53 NaN
33 1999 10 7 NaN
94 2004 11 52 NaN
100 2005 5 38 NaN
163 2010 8 6 NaN
182 2012 3 25 NaN
188 2012 9 22 NaN
278 2020 3 53 NaN
294 2021 7 9 NaN
要获得每年 的异常值,您需要通过 groupby
计算每年的四分位数。除此之外,您的代码没有太大变化,但我最近了解到 between
在这里似乎很有用:
import numpy as np
clean_data = list()
for year, group in DF.groupby('year'):
Q1 = group['SAL'].quantile(0.25)
Q3 = group['SAL'].quantile(0.75)
IQR = Q3 - Q1
# set all values to np.nan that are not (~) in between the two values
group.loc[~group['SAL'].between(Q1 - 1.5 * IQR,
Q3 + 1.5 * IQR,
inclusive=False),
'SAL'] = np.nan
clean_data.append(group)
clean_df = pd.concat(clean_data)
我开始使用 python 并且我正在尝试使用分位数找出每年的异常值 我的数据组织如下: 年列,每年我都有几个月及其相应的盐度和温度
year=[1997:2021]
month=[1,2...]
SAL=[33,32,50,......,35,...]
以下是我的代码:
#1st quartile
Q1 = DF['SAL'].quantile(0.25)
#3rd quartile
Q3 = DF['SAL'].quantile(0.75)
#calculate IQR
IQR = Q3 - Q1
print(IQR)
df_out = DF['SAL'][((DF['SAL'] < (Q1 - 1.5 * IQR)) |(DF['SAL'] > (Q3 + 1.5 * IQR)))]
我想识别异常值的月份和年份,并用nan替换它。
您可以使用以下功能。它使用低于 Q1-1.5IQR 或高于 Q3+1.5IQR 的离群值定义,例如箱线图的经典定义。
import pandas as pd
import numpy as np
df = pd.DataFrame({'year': np.repeat(range(1997,2022), 12),
'month': np.tile(range(12), 25)+1,
'SAL': np.random.randint(20,40, size=12*25)+np.random.choice([0,-20, 20], size=12*25, p=[0.9,0.05,0.05]),
})
def outliers(s, replace=np.nan):
Q1, Q3 = np.percentile(s, [25 ,75])
IQR = Q3-Q1
return s.where((s > (Q1 - 1.5 * IQR)) & (s < (Q3 + 1.5 * IQR)), replace)
# add new column with excluded outliers
df['SAL_excl'] = df.groupby('year')['SAL'].apply(outliers)
检查它是否有效:
异常值:
import seaborn as sns
sns.boxplot(data=df, x='year', y='SAL')
没有异常值:
sns.boxplot(data=df, x='year', y='SAL_excl')
注意。由于过滤,新的异常值可能会出现,因为数据现在有了新的 Q1/Q3/IQR。
如何检索带有离群值的行:
df[df['SAL_excl'].isna()]
输出:
year month SAL SAL_excl
28 1999 5 53 NaN
33 1999 10 7 NaN
94 2004 11 52 NaN
100 2005 5 38 NaN
163 2010 8 6 NaN
182 2012 3 25 NaN
188 2012 9 22 NaN
278 2020 3 53 NaN
294 2021 7 9 NaN
要获得每年 的异常值,您需要通过 groupby
计算每年的四分位数。除此之外,您的代码没有太大变化,但我最近了解到 between
在这里似乎很有用:
import numpy as np
clean_data = list()
for year, group in DF.groupby('year'):
Q1 = group['SAL'].quantile(0.25)
Q3 = group['SAL'].quantile(0.75)
IQR = Q3 - Q1
# set all values to np.nan that are not (~) in between the two values
group.loc[~group['SAL'].between(Q1 - 1.5 * IQR,
Q3 + 1.5 * IQR,
inclusive=False),
'SAL'] = np.nan
clean_data.append(group)
clean_df = pd.concat(clean_data)