You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas DataFrame多列移除异常值:apply函数报错及循环实现求助

问题与解决方案

问题背景

我有一个大型Pandas DataFrame,以下是可复现的示例数据:

data = {'X1': [3,5,8,3,5,19,5],
        'X2': [2,7,9,1,14,2,10],
        'X3': [1,8,23,14,4,9,5],
        'X4': [5,3,1,6,9,23,12]}

df = pd.DataFrame.from_dict(data)

我想给所有特征移除异常值,试了apply函数但报错,同时也想知道怎么用for循环实现。下面是我写的两段代码:

第一段:apply函数尝试代码

def remove(df):
    for i in df:
        Q1 = df[i].quantile(0.25)
        Q3 = df[i].quantile(0.75)
        IQR = Q3 - Q1
        lower = (Q1 - 1.5*IQR)
        upper = (Q3 + 1.5*IQR)
         
        upper_array = np.where(df[i] >= upper)[0]
        lower_array = np.where(df[i] <= lower)[0]
    
    df.drop(index=upper_array, inplace=True)
    df.drop(index=lower_array, inplace=True)

    return df

df = df.apply(remove,axis=1)
df.head()

第二段:for循环尝试代码

lower = []
upper = []
for i in df:
    Q1 = df[i].quantile(0.25)
    Q3 = df[i].quantile(0.75)
    IQR = Q3 - Q1
    lower.append(Q1 - 1.5*IQR)
    upper.append(Q3 + 1.5*IQR)
    
for i in df:
        upper_array = np.where(df[i] >= upper)[0]
        lower_array = np.where(df[i] <= lower)[0]

df.drop(index=upper_array, inplace=True)
df.drop(index=lower_array, inplace=True)

错误分析与修复

一、apply代码的问题

你用df.apply(remove, axis=1)时,axis=1会把每一行作为Series传入remove函数,但你的函数是针对整个DataFrame的列计算分位数,逻辑完全不匹配,肯定报错。另外,函数里的循环也有问题:每次循环处理一列,但你在循环外才执行drop,最后只会保留最后一列的异常值索引,前面列的处理全被覆盖了。

正确实现(不用apply更高效)

其实不需要用apply,直接对整个DataFrame计算每列的上下界,然后过滤行:

import pandas as pd
import numpy as np

data = {'X1': [3,5,8,3,5,19,5],
        'X2': [2,7,9,1,14,2,10],
        'X3': [1,8,23,14,4,9,5],
        'X4': [5,3,1,6,9,23,12]}

df = pd.DataFrame.from_dict(data)

# 计算所有列的Q1、Q3和IQR
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

# 过滤掉任意一列超出上下界的行
df_filtered = df[~((df < lower_bound) | (df > upper_bound)).any(axis=1)]
print(df_filtered)

二、for循环代码的问题

  1. 你把每列的上下界存在列表lower和upper里,但后续循环时,df[i] >= upper是把列和整个列表比较,维度不匹配,直接报错。
  2. 第二个循环里,每次循环都会覆盖upper_array和lower_array,最后只会处理最后一列的异常值,前面列的异常值完全没被处理。
  3. 直接用inplace=True多次drop会导致索引混乱,因为drop后行索引会变化,后续drop的索引可能对应错误的行。

正确的for循环实现

先收集所有需要删除的行索引,最后一次性删除:

import pandas as pd
import numpy as np

data = {'X1': [3,5,8,3,5,19,5],
        'X2': [2,7,9,1,14,2,10],
        'X3': [1,8,23,14,4,9,5],
        'X4': [5,3,1,6,9,23,12]}

df = pd.DataFrame.from_dict(data)

# 用集合存要删除的索引,自动去重
drop_indices = set()

for col in df.columns:
    Q1 = df[col].quantile(0.25)
    Q3 = df[col].quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    
    # 找到当前列的异常值索引
    upper_indices = df[df[col] >= upper].index
    lower_indices = df[df[col] <= lower].index
    
    # 加入待删除集合
    drop_indices.update(upper_indices)
    drop_indices.update(lower_indices)

# 一次性删除所有异常值行
df_filtered = df.drop(drop_indices)
print(df_filtered)

内容的提问来源于stack exchange,提问作者Raagib khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:40:57