如何在Pandas DataFrame中筛选col1/col2/col3同值、col4异值的行?有无更优方案?
问题:定位DataFrame中col1、col2、col3取值相同但col4取值不同的行
需求明确:在Pandas DataFrame内,筛选出col1、col2、col3三者取值完全一致,但col4取值存在差异的行;同时按col0分组后,每组内每个(col1, col2)组合只保留按col4排序后的第一行。
用户原始实现代码:
import pandas as pd data = { 'col0': ['A', 'A', 'A', 'B', 'B', 'C'], 'col1': [1, 1, 1, 2, 2, 3], 'col2': [1, 1, 1, 2, 2, 3], 'col3': [1, 2, 3, 1, 2, 1], 'col4': [10, 20, 30, 40, 50, 60] } df = pd.DataFrame(data) df = df.sort_values(by='col4') df['same_col1_col2'] = df.duplicated(subset=['col1', 'col2'], keep=False) df['different_col3'] = df.groupby(['col1', 'col2'])['col3'].transform('nunique') > 1 df['final_flag'] = df['same_col1_col2'] & df['different_col3'] df_result = pd.DataFrame(columns=df.columns) for symbol in df['col0'].unique(): df_symbol = df[df['col0'] == symbol] df_filtered = df_symbol[df_symbol['final_flag']].drop_duplicates(subset=['col1', 'col2'], keep='first') df_result = pd.concat([df_result, df_filtered]) df_result = df_result.drop(columns=['same_col1_col2', 'different_col3', 'final_flag']).reset_index(drop=True) print(df_result)
优化实现方案
可以通过更简洁的分组筛选逻辑实现,避免冗余列和循环拼接,提升代码可读性与执行效率:
import pandas as pd data = { 'col0': ['A', 'A', 'A', 'B', 'B', 'C'], 'col1': [1, 1, 1, 2, 2, 3], 'col2': [1, 1, 1, 2, 2, 3], 'col3': [1, 2, 3, 1, 2, 1], 'col4': [10, 20, 30, 40, 50, 60] } df = pd.DataFrame(data) # 先按col4排序,确保后续取第一行的顺序符合需求 df_sorted = df.sort_values(by='col4') # 核心逻辑:先筛选出(col1,col2,col3)相同但col4有不同值的行,再按(col0,col1,col2)分组取第一行 df_result = ( df_sorted .groupby(['col1', 'col2', 'col3']) .filter(lambda group: group['col4'].nunique() > 1) .groupby(['col0', 'col1', 'col2']) .first() .reset_index() ) print(df_result)
优化点说明
- 移除冗余辅助列:无需创建
same_col1_col2等中间列,直接通过groupby.filter完成目标分组筛选 - 替换循环拼接:用Pandas链式调用替代
for循环+pd.concat,代码更紧凑,大数据量下执行效率更高 - 逻辑更直观:先锁定
col1/col2/col3相同但col4不同的行,再按col0+col1+col2分组保留第一行,完全匹配需求
补充:若需求为「col1、col2相同,且组内存在col3相同但col4不同的行」
如果你的实际需求是同一(col1, col2)组内,存在部分col3相同但对应的col4不同的行,可调整筛选逻辑如下:
df_result = ( df_sorted # 先筛选出(col1,col2)组内存在(col3相同但col4不同)的情况 .groupby(['col1', 'col2']) .filter(lambda g: g.groupby('col3')['col4'].nunique().gt(1).any()) # 按(col0,col1,col2)分组取第一行 .groupby(['col0', 'col1', 'col2']) .first() .reset_index() )
内容的提问来源于stack exchange,提问作者Alan Chau
相关产品推荐
相关产品推荐

