【发布时间】:2016-01-14 05:03:34
【问题描述】:
是否有内置方法可以按 IQR(即 Q1-1.5IQR 和 Q3+1.5IQR 之间的值)对列进行过滤? 另外,建议使用 pandas 中任何其他可能的广义过滤。
【问题讨论】:
标签: python pandas data-processing iqr
是否有内置方法可以按 IQR(即 Q1-1.5IQR 和 Q3+1.5IQR 之间的值)对列进行过滤? 另外,建议使用 pandas 中任何其他可能的广义过滤。
【问题讨论】:
标签: python pandas data-processing iqr
据我所知,最紧凑的符号似乎是由query 方法带来的。
# Some test data
np.random.seed(33454)
df = (
# A standard distribution
pd.DataFrame({'nb': np.random.randint(0, 100, 20)})
# Adding some outliers
.append(pd.DataFrame({'nb': np.random.randint(100, 200, 2)}))
# Reseting the index
.reset_index(drop=True)
)
# Computing IQR
Q1 = df['nb'].quantile(0.25)
Q3 = df['nb'].quantile(0.75)
IQR = Q3 - Q1
# Filtering Values between Q1-1.5IQR and Q3+1.5IQR
filtered = df.query('(@Q1 - 1.5 * @IQR) <= nb <= (@Q3 + 1.5 * @IQR)')
然后我们可以绘制结果来检查差异。我们观察到左侧箱线图中的异常值(183 处的十字)不再出现在过滤后的系列中。
# Ploting the result to check the difference
df.join(filtered, rsuffix='_filtered').boxplot()
自从有了这个答案,我就这个话题写了post,如果你可以找到更多信息。
【讨论】:
df.join(filtered, rsuffix='_filtered').boxplot() 对此不起作用。
Q1, Q3 = df['nb'].quantile([.25, .75])来缩短
使用Series.between()的另一种方法:
iqr = df['col'][df['col'].between(df['col'].quantile(.25), df['col'].quantile(.75), inclusive=True)]
抽出:
# Select the first quantile
q1 = df['col'].quantile(.25)
# Select the third quantile
q3 = df['col'].quantile(.75)
# Create a mask inbeetween q1 & q3
mask = df['col'].between(q1, q3, inclusive=True)
# Filtering the initial dataframe with a mask
iqr = df.loc[mask, 'col']
【讨论】:
这将为您提供df 的子集,它位于column 列的 IQR:
def subset_by_iqr(df, column, whisker_width=1.5):
"""Remove outliers from a dataframe by column, including optional
whiskers, removing rows for which the column value are
less than Q1-1.5IQR or greater than Q3+1.5IQR.
Args:
df (`:obj:pd.DataFrame`): A pandas dataframe to subset
column (str): Name of the column to calculate the subset from.
whisker_width (float): Optional, loosen the IQR filter by a
factor of `whisker_width` * IQR.
Returns:
(`:obj:pd.DataFrame`): Filtered dataframe
"""
# Calculate Q1, Q2 and IQR
q1 = df[column].quantile(0.25)
q3 = df[column].quantile(0.75)
iqr = q3 - q1
# Apply filter with respect to IQR, including optional whiskers
filter = (df[column] >= q1 - whisker_width*iqr) & (df[column] <= q3 + whisker_width*iqr)
return df.loc[filter]
# Example for whiskers = 1.5, as requested by the OP
df_filtered = subset_by_iqr(df, 'column_name', whisker_width=1.5)
【讨论】:
>=和<=改成>和<吗?
1.5的胡须。我现在将这些作为一个选项包含在内,因为这是一个非常依赖于数据集的超参数。
使用df.quantile 查找第一个和第三个四分位数,然后在数据帧上使用掩码。
如果您想删除它们,请使用no_outliers 并反转掩码中的条件以获得outliers。
Q1 = df.col.quantile(0.25)
Q3 = df.col.quantile(0.75)
IQR = Q3 - Q1
no_outliers = df.col[(Q1 - 1.5*IQR < df.BMI) & (df.BMI < Q3 + 1.5*IQR)]
outliers = df.col[(Q1 - 1.5*IQR >= df.BMI) | (df.BMI >= Q3 + 1.5*IQR)]
【讨论】:
另一种方法使用 Series.clip:
q = s.quantile([.25, .75])
s = s[~s.clip(*q).isin(q)]
详情如下:
s = pd.Series(np.randon.randn(100))
q = s.quantile([.25, .75]) # calculate lower and upper bounds
s = s.clip(*q) # assigns values outside boundary to boundary values
s = s[~s.isin(q)] # take only observations within bounds
使用它来过滤整个数据框df 很简单:
def iqr(df, colname, bounds = [.25, .75]):
s = df[colname]
q = s.quantile(bounds)
return df[~s.clip(*q).isin(q)]
注意:该方法本身不包括边界。
【讨论】:
您也可以通过计算 IQR 来尝试使用以下代码。基于 IQR、下限和上限,它将替换每列中显示的异常值。此代码将遍历数据框中的每一列,并通过单独过滤异常值来逐一工作,而不是遍历行中的所有值来查找异常值。
功能:
def mod_outlier(df):
df1 = df.copy()
df = df._get_numeric_data()
q1 = df.quantile(0.25)
q3 = df.quantile(0.75)
iqr = q3 - q1
lower_bound = q1 -(1.5 * iqr)
upper_bound = q3 +(1.5 * iqr)
for col in col_vals:
for i in range(0,len(df[col])):
if df[col][i] < lower_bound[col]:
df[col][i] = lower_bound[col]
if df[col][i] > upper_bound[col]:
df[col][i] = upper_bound[col]
for col in col_vals:
df1[col] = df[col]
return(df1)
函数调用:
df = mod_outlier(df)
【讨论】: