Pandas GroupBy对象迭代列实现多列IQR异常值删除的方法问询
通用实现方案
原代码存在变量名混淆的问题:初始化的结果变量为rent,但拼接新数据后赋值给了aluguel,会导致最终结果为空,以下通用方案已修正该问题,可适配任意指定的数值列。
方案1:与原有逻辑对齐的循环实现
逻辑和你现有写法完全一致,仅增加了数值列迭代逻辑,更容易理解和调试:
import pandas as pd # 自定义要纳入异常值判断的数值列,也可以自动筛选数值列 numeric_cols = ["Rent_Price", "nº of bedrooms", "parking spaces", "floor area"] # 自动筛选数值列写法(如果要排除index列可以加.drop('index')) # numeric_cols = df.select_dtypes(include='number').columns.tolist() # 按行政区分组计算所有数值列的IQR上下限 boroughs = df.groupby(by="Borough") Q1 = boroughs[numeric_cols].quantile(0.25) Q3 = boroughs[numeric_cols].quantile(0.75) IQR = Q3 - Q1 inf_lim = Q1 - 1.5 * IQR sup_lim = Q3 + 1.5 * IQR # 初始化清洗后的结果表 df_clean = pd.DataFrame() for borough in boroughs.groups.keys(): # 筛选当前行政区的行 borough_mask = df["Borough"] == borough # 迭代所有数值列,拼接非异常条件:所有列都在IQR范围内才保留 not_outlier_mask = True for col in numeric_cols: col_mask = (df[col] >= inf_lim.loc[borough, col]) & (df[col] <= sup_lim.loc[borough, col]) not_outlier_mask = not_outlier_mask & col_mask # 合并条件筛选并拼接结果 final_mask = borough_mask & not_outlier_mask df_clean = pd.concat([df_clean, df[final_mask]], ignore_index=True)
方案2:更高效的向量化实现(无需显式循环)
利用pandas分组apply特性,代码更简洁,大数据量下运行效率更高:
def remove_group_outliers(group, cols): # 计算当前分组内指定列的IQR上下限 q1 = group[cols].quantile(0.25) q3 = group[cols].quantile(0.75) iqr = q3 - q1 lower_limit = q1 - 1.5 * iqr upper_limit = q3 + 1.5 * iqr # 所有列都满足非异常条件的行才保留 keep_mask = ((group[cols] >= lower_limit) & (group[cols] <= upper_limit)).all(axis=1) return group[keep_mask] # 自定义要处理的数值列 numeric_cols = ["Rent_Price", "nº of bedrooms", "parking spaces", "floor area"] df_clean = df.groupby("Borough", group_keys=False).apply(remove_group_outliers, cols=numeric_cols).reset_index(drop=True)
注意事项
- 代码中的列名需和你实际DataFrame中的列名大小写、拼写完全一致,避免匹配报错
- 两种方案的逻辑规则一致:某行数据需要在所属行政区的所有指定数值列的IQR范围内,才会被保留
内容的提问来源于stack exchange,提问作者Julio Burlamaqui
相关产品推荐
相关产品推荐

