Pandas按多列组合分组应用IQR法检测异常值报错修复
问题根源
原代码存在4处核心错误,直接触发报错或逻辑失效:
- 用
zip(itr1, itr2)遍历两列唯一值的写法错误:zip只会按位置一一配对元素,不会生成两个维度所有合法的分组组合,当两列唯一值数量不一致时,会直接丢失部分分组,后续计算时出现维度不匹配的广播错误。 - 循环内重复计算全量分组的四分位值:循环中写的
df.groupby(...)是对全表做分组统计,完全没有用到当前遍历的分组键(i,j)筛选对应分组数据,计算完全冗余。 - 遍历groupby对象的取值逻辑错误:
for x in df.groupby(...)[variable]拿到的x是(分组键名, 分组对应Series)的元组,不是单个数值,直接和阈值做比较会触发形状不匹配的报错。 - 循环内提前return:第一次循环执行完就直接返回结果,根本不会遍历完所有分组。
修复方案
不需要写显式循环遍历分组,用pandas内置的transform方法可以直接把每个分组计算得到的阈值映射回原表每一行,代码更简洁、运行效率更高:
import pandas as pd def tukeys_method(df, variable, group_col1, group_col2): # 按指定两个维度分组,计算每组目标列的统计值并映射回原表每一行 grouped = df.groupby([group_col1, group_col2])[variable] q1 = grouped.transform('quantile', 0.25) q3 = grouped.transform('quantile', 0.75) iqr = q3 - q1 # 计算各层级异常值围栏 inner_low = q1 - 1.5 * iqr inner_high = q3 + 1.5 * iqr outer_low = q1 - 3 * iqr outer_high = q3 + 3 * iqr # 提取异常值对应的原表索引 # 极异常值:超出3倍IQR围栏 probable_outliers = df.index[(df[variable] <= outer_low) | (df[variable] >= outer_high)].tolist() # 潜在异常值:超出1.5倍IQR围栏 possible_outliers = df.index[(df[variable] <= inner_low) | (df[variable] >= inner_high)].tolist() return probable_outliers, possible_outliers # 函数调用 probable_outliers_tm, possible_outliers_tm = tukeys_method(df, "Price", "Region", "Product")
测试结果说明
注意你提供的样例数据构造代码中,Uganda对应的Product值写为XYZ,和上方表格中记录的ABC不一致,修正为一致后运行函数:
- 无超出3倍IQR的极异常值,
probable_outliers_tm返回空列表 - 潜在异常值共2个,对应索引为:
- South Africa 2018年Price=15的记录
- Japan 2019年Price=0的记录
- Uganda 2018年Price=1300的记录在对应分组的正常波动范围内,不会被识别为异常值。
内容的提问来源于stack exchange,提问作者A.N.
相关产品推荐
相关产品推荐

