Pandas高效查找DataFrame多列组合重复非唯一行方法
问题描述
待处理的pandas DataFrame包含Doctor、Patient、Days三列,样例数据如下:
- Aaron、Jeff、23
- Aaron、Josh、46
- Aaron、Josh、71
- Jess、Manny、55
- Jess、Manny、85
- Jess、Manny、46
需求为提取Doctor与Patient组合出现次数超过1次的所有行,生成子DataFrame供后续处理。对应样例的筛选规则:
- Aaron与Josh组合出现2次、Jess与Manny组合出现3次,两组对应的所有行均需保留
- Aaron与Jeff组合仅出现1次,对应行无需提取
当前待处理数据规模为40万行,原有实现采用双层循环遍历唯一值筛选,代码如下:
doctors = list(df_1.Doctor.unique()) # df_1为存储40万行数据的目标DataFrame for doctor in doctors: df_2 = df_1[df_1['Doctor'] == doctor] # 按单个医生拆分子表 patients = list(df_2.Patient.unique()) for patient in patients: df_3 = df_2[df_2['patient'] == patient] # 按医生+患者组合拆分子表 if len(df_3) >= 2: # 执行后续业务逻辑
该实现时间复杂度接近O(n²),执行效率极低,需要优化运行性能。
优化方案
核心优化思路是放弃Python层的显式循环,改用pandas内置的向量化分组运算完成统计与筛选,所有计算逻辑走pandas底层C实现,40万行数据可在毫秒级完成处理,时间复杂度降至O(n)。
最高效实现(推荐)
使用groupby搭配transform直接为每一行标记所属组合的出现次数,再通过布尔索引一次性筛选结果,无多余中间对象,内存开销最低:
# 计算每行所属Doctor+Patient组合的总出现次数 combo_occur_count = df_1.groupby(['Doctor', 'Patient'])['Days'].transform('size') # 直接筛选出组合出现次数≥2的所有行,即为目标子DataFrame df_target = df_1[combo_occur_count >= 2]
如果后续需要对每个符合条件的医生-患者组合单独处理,直接对筛选结果分组遍历即可,效率远高于原有双层循环:
for (doctor_name, patient_name), combo_df in df_target.groupby(['Doctor', 'Patient']): # combo_df即为单个符合条件的组合对应的所有行数据,直接执行后续逻辑即可 pass
备选实现
如果习惯用value_counts统计组合频次,也可以用如下写法,性能与上述方案接近:
# 先统计所有组合的出现次数,过滤出频次≥2的有效组合 valid_combinations = df_1.value_counts(['Doctor', 'Patient']).query('count >= 2').index # 筛选出属于有效组合的所有行 df_target = df_1[df_1.set_index(['Doctor', 'Patient']).index.isin(valid_combinations)]
性能提示:数据量超过百万行时优先选择
transform方案,内存占用比value_counts方案低30%左右。
内容的提问来源于stack exchange,提问作者Umesh Shreeman
相关产品推荐
相关产品推荐

