Pandas如何删除DataFrame各分组内width最小的4行数据?
问题说明
需要使用Python pandas处理CSV数据,实现逻辑:
- 按
id字段对数据分组 - 删除每个分组内
width列值最小的4行记录
原有代码调用groupby.filter()时触发报错:TypeError: 'Int64Index' object is not callable
报错原因
groupby.filter()方法的入参要求是可调用的判断函数,作用是判定整个分组是否保留,不支持直接传入待删除的行索引对象。传入Int64Index类型的索引后,pandas会尝试将其作为函数调用,因此触发类型错误。
正确实现方案
方案1:基于原有索引逻辑修正
你之前获取待删除行索引的思路是可行的,只需要放弃用filter方法,直接在原始DataFrame上按索引删除对应行即可,注意对索引去重避免异常:
if args.process_log: datafile = pd.read_csv(args.out_log) grouped_data = datafile.groupby('id') # 提取每个分组内width最小的4行 datagroup_smallest = grouped_data.apply(lambda x: x.nsmallest(n=4, columns='width')) # 提取待删除行对应的原始索引,去重避免索引重复导致的删除异常 unwanted_index = datagroup_smallest.index.get_level_values(1).unique() # 直接按索引删除目标行 data_splitted = datafile.drop(index=unwanted_index)
方案2:单步分组处理(更简洁)
不需要单独提取待删除索引,直接在分组apply逻辑中完成行筛选即可,逻辑更直观:
if args.process_log: datafile = pd.read_csv(args.out_log) # 按id分组,每个分组内按width升序排序后跳过前4行(即删除width最小的4行) data_splitted = datafile.groupby('id', group_keys=False).apply( lambda x: x.sort_values('width', ascending=True).iloc[4:] )
注意:如果你的业务需求是「分组内行数不足4行时保留所有行,不做删除」,将切片逻辑修改为
iloc[min(4, len(x)):]即可;如果需要分组不足4行时全部删除,保持原有iloc[4:]写法即可。
额外说明
groupby.filter()的适用场景是整组筛选,比如过滤掉行数不足5条的全部分组、过滤掉width均值小于10的全部分组这类需求,不适合做分组内的细粒度行筛选。
内容的提问来源于stack exchange,提问作者Maria Sabrina Ma
相关产品推荐
相关产品推荐

