使用Pandas删除id分组内首次出现success=Y后的多余行
实现方案
核心逻辑:先按id分组,截取每组从第一行到**首次出现success == 'Y'的行(包含该行)**的所有记录,若组内无success == 'Y'的记录则保留全部行。处理前需先按id、year排序,避免行顺序错乱导致截取错误。
方案1:直观易读版(适合中小数据量)
用分组自定义函数实现,逻辑清晰方便排查问题:
import pandas as pd # 先按id、年份排序,保证行顺序符合时间逻辑 df = df.sort_values(by=['id', 'year']).reset_index(drop=True) def filter_post_y_rows(group): # 定位组内所有success为Y的行索引 y_row_index = group.index[group['success'] == 'Y'] if len(y_row_index) == 0: # 组内无Y记录,返回全部行 return group # 有Y记录时,截断到第一个Y所在的行(包含该行) return group.loc[:y_row_index[0]] # 分组应用过滤逻辑 result_df = df.groupby('id', group_keys=False).apply(filter_post_y_rows).reset_index(drop=True)
方案2:高性能向量化版(适合大数据量)
基于pandas内置的累计运算实现,无逐组循环,处理百万行以上数据时速度优势明显:
import pandas as pd # 先按id、年份排序 df = df.sort_values(by=['id', 'year']).reset_index(drop=True) # 标记Y行,计算组内累计是否已出现Y df['is_y'] = df['success'].eq('Y') df['has_y_before'] = df.groupby('id')['is_y'].cummax() # 错位标记首次Y之后的行:错位后为True的行就是需要删除的行 df['drop_flag'] = df.groupby('id')['has_y_before'].shift(fill_value=False) # 过滤掉需要删除的行,清理临时列 result_df = df[~df['drop_flag']].drop(columns=['is_y', 'has_y_before', 'drop_flag']).reset_index(drop=True)
效果验证
两种方案运行后输出结果完全匹配预期:
id==1组截断到2002年首次出现Y的行,删除2003、2004年的后续记录id==2组无Y记录,保留全部3行id==3组Y出现在组内最后一行,无多余行需要删除,保留全部记录
内容的提问来源于stack exchange,提问作者floss
相关产品推荐
相关产品推荐

