如何根据DataFrame中的模式变化删除重复行?
保留连续重复模式的首行(跳过跨模式重复)
问题场景
现有如下包含ID、日期和各类别百分比的DataFrame:
import pandas as pd df = pd.DataFrame({"ID":["A","A","A","A","A","A","A"], "DATE":["01-1990","03-1990","04-1990","05-1990","06-1990","07-1990", "08-1990"], "CLASS A":[30,30,0,0,0,30,30], "CLASS B":[50,50,50,50,50,50,50], "CLASS C":[20,20,50,50,50,20,20]})
原始数据输出:
ID DATE CLASS A CLASS B CLASS C 0 A 01-1990 30 50 20 1 A 03-1990 30 50 20 2 A 04-1990 0 50 50 3 A 05-1990 0 50 50 4 A 06-1990 0 50 50 5 A 07-1990 30 50 20 6 A 08-1990 30 50 20
需求说明
需要基于ID、CLASS A、CLASS B、CLASS C列,仅删除连续重复组内的重复行并保留首行;对于跨模式的重复(比如本例中首尾的30/50/20模式),需保留新出现的该模式的首行。最终期望结果:
ID DATE CLASS A CLASS B CLASS C 0 A 01-1990 30 50 20 2 A 04-1990 0 50 50 5 A 07-1990 30 50 20
注意:直接使用df.drop_duplicates(subset=['ID','CLASS A','CLASS B','CLASS C'], keep='first')会删除索引5、6的行,无法满足需求。
解决方案
核心思路是识别连续的重复组,只保留每个组的第一行,以下是两种可行方法:
方法1:用shift()标记模式变化行
通过对比当前行与上一行的目标列是否一致,筛选出模式变化的行(包含第一行):
# 生成标记:当前行与上一行模式不一致则为True mask = df[['ID','CLASS A','CLASS B','CLASS C']].ne(df[['ID','CLASS A','CLASS B','CLASS C']].shift()).any(axis=1) # 筛选符合条件的行 result = df[mask]
方法2:用groupby结合连续组ID分组
先生成连续重复组的标识,再按组取首行:
# 生成连续组ID:模式变化时ID递增 group_id = (df[['ID','CLASS A','CLASS B','CLASS C']].ne(df[['ID','CLASS A','CLASS B','CLASS C']].shift()).any(axis=1)).cumsum() # 按组ID分组,保留每组第一行 result = df.groupby(group_id).first().reset_index(drop=True)
两种方法均能得到期望结果,其中方法1更简洁高效。
内容的提问来源于stack exchange,提问作者user026
相关产品推荐
相关产品推荐

