如何用IQR法移除多列DataFrame中的异常值?
使用IQR方法移除DataFrame多列异常值的解决方案
我来帮你解决这两个问题,一步步拆解:
问题1:如何根据IQR统计结果移除所有异常值
你已经写出了标记异常值的核心代码,其实只要基于这个标记矩阵,就能轻松筛选出干净的数据行。
首先把你的异常值标记逻辑封装成一个mask矩阵:
Q1 = stepframe.quantile(0.25) Q3 = stepframe.quantile(0.75) IQR = Q3 - Q1 # 生成每个单元格是否为异常值的布尔矩阵 outlier_mask = ((stepframe < (Q1 - 1.5 * IQR)) | (stepframe > (Q3 + 1.5 * IQR)))
接下来分两种场景处理:
- 移除所有列中存在异常值的行(即保留所有列都无异常值的行):
clean_df = stepframe.loc[~outlier_mask.any(axis=1)] - 只移除特定列的异常值(比如你结果里的
Step_Count列):clean_df = stepframe.loc[~outlier_mask['Step_Count']]
问题2:自定义函数传多列报错的解决方法
你的自定义函数是为单列处理设计的,但你传入了stepframe.columns(一个多列的列表),导致df_in[col_name]返回了多列DataFrame,进而触发ValueError。这里有两种可行的修复方式:
方式1:循环遍历每一列逐步过滤
如果希望依次对每一列移除异常值,可以循环调用你的函数:
def remove_outlier(df_in, col_name): q1 = df_in[col_name].quantile(0.25) q3 = df_in[col_name].quantile(0.75) iqr = q3 - q1 fence_low = q1 - 1.5 * iqr fence_high = q3 + 1.5 * iqr df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)] return df_out # 初始化干净数据集为原数据 clean_df = stepframe.copy() # 循环处理每一列 for col in stepframe.columns: clean_df = remove_outlier(clean_df, col)
注意:这种方式是逐步过滤,每一步都会移除当前列的异常值,最终得到的是所有列都无异常值的行。
方式2:批量处理所有列(更高效)
对于100列的数据集,批量向量运算比循环更快,直接复用问题1的逻辑封装成函数:
def remove_outliers_batch(df): # 仅对数值列计算IQR(避免非数值列报错) numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns Q1 = df[numeric_cols].quantile(0.25) Q3 = df[numeric_cols].quantile(0.75) IQR = Q3 - Q1 # 生成异常值mask,非数值列自动跳过 outlier_mask = ((df[numeric_cols] < (Q1 - 1.5 * IQR)) | (df[numeric_cols] > (Q3 + 1.5 * IQR))) outlier_mask = outlier_mask.reindex(columns=df.columns, fill_value=False) # 保留无异常值的行 return df.loc[~outlier_mask.any(axis=1)] clean_df = remove_outliers_batch(stepframe)
额外提示
如果你的DataFrame包含非数值列(比如Day列),一定要记得只对数值列计算IQR,避免引发类型错误。上面的批量处理函数已经帮你做了这一步,你可以直接用。
内容的提问来源于stack exchange,提问作者Imran Ahmad Ghazali
相关产品推荐
相关产品推荐

