基于GroupBy筛选DataFrame:出现Payment Activity后删除后续行
问题描述
现有DataFrame如下:
ID Activity Action No. A1 register 1 A1 fill form 2 A2 Payment Done 3 A2 fill form 2 B1 fill form 1 B1 Payment Done 2 B1 Process_drop 3 B1 fill form 1
需求是:当某个ID执行了Payment Done操作后,删除该操作之后的所有行,最终期望得到的DataFrame如下:
ID Activity Action No. A1 register 1 A1 fill form 2 A2 Payment Done 3 B1 fill form 1 B1 Payment Done 2
解决方法
这里提供两种基于Pandas的可行实现方式:
方法一:分组定位截断
按ID分组后,找到每组中第一个Payment Done的位置,保留该行及之前的所有记录;如果组内没有该操作,则保留全部行。
代码实现:
import pandas as pd # 构造示例数据 df = pd.DataFrame({ 'ID': ['A1', 'A1', 'A2', 'A2', 'B1', 'B1', 'B1', 'B1'], 'Activity': ['register', 'fill form', 'Payment Done', 'fill form', 'fill form', 'Payment Done', 'Process_drop', 'fill form'], 'Action No.': [1, 2, 3, 2, 1, 2, 3, 1] }) def filter_group(group): # 获取组内第一个Payment Done的索引 payment_pos = group[group['Activity'] == 'Payment Done'].index if not payment_pos.empty: # 保留到该索引的所有行 return group.loc[:payment_pos[0]] # 没有Payment Done则返回原组 return group # 应用分组过滤 result = df.groupby('ID', group_keys=False).apply(filter_group) print(result)
方法二:累积标记过滤
通过分组计算累积标记,标记出Payment Done出现的位置,只保留标记值≤1的行(即未出现Payment,或刚好是Payment的那一行)。
代码实现:
import pandas as pd # 构造示例数据 df = pd.DataFrame({ 'ID': ['A1', 'A1', 'A2', 'A2', 'B1', 'B1', 'B1', 'B1'], 'Activity': ['register', 'fill form', 'Payment Done', 'fill form', 'fill form', 'Payment Done', 'Process_drop', 'fill form'], 'Action No.': [1, 2, 3, 2, 1, 2, 3, 1] }) # 分组标记:每出现一次Payment Done,累积值加1 df['payment_flag'] = df.groupby('ID')['Activity'].transform(lambda x: x.eq('Payment Done').cumsum()) # 只保留累积值为0(未出现Payment)或1(首次Payment行)的记录 result = df[(df['payment_flag'] <= 1)].drop('payment_flag', axis=1) print(result)
两种方法都能得到你期望的结果,可根据实际场景选择更适合的方式。
内容的提问来源于stack exchange,提问作者Roshankumar
相关产品推荐
相关产品推荐

