使用Pandas按ID分组统计连续出现的(L1,L2)事件次数
统计同一事件连续出现的次数
需求:统计同一(L1, L2)事件在每个id分组内连续循环出现的次数,规则如下:
- 仅统计连续循环出现的事件,若中间插入其他事件,后续出现的相同事件视为新循环
- 最终输出每个
id下符合条件的事件及其累计循环次数
示例输入数据
id date L1 L2 1 1/8 A B 1 2/8 B C 1 3/8 B A 2 2/8 A B 2 3/8 B A 2 4/8 A B 3 5/8 A B 3 6/8 B A 3 7/8 B C 3 8/8 C A 3 8/8 A B
目标输出结果
id L1 L2 count 2 A B 3 3 A B 2
规则说明
- ID 1未被统计:
A-B事件之后没有连续循环出现相同事件 - ID 3的
A-B计为2:中间插入了B-C等其他事件,后续的A-B属于新循环,累计次数为2
解决思路
- 按
id分组,处理每个分组内的事件序列 - 识别连续循环事件:判断当前事件是否是前一事件的逆序(如
(A,B)→(B,A)→(A,B)) - 为连续循环的事件序列标记分组,统计每组内的事件出现次数
- 筛选出符合条件的循环事件,整理成目标格式
代码实现
import pandas as pd # 构造示例数据 data = { 'id': [1,1,1,2,2,2,3,3,3,3,3], 'date': ['1/8','2/8','3/8','2/8','3/8','4/8','5/8','6/8','7/8','8/8','8/8'], 'L1': ['A','B','B','A','B','A','A','B','B','C','A'], 'L2': ['B','C','A','B','A','B','B','A','C','A','B'] } df = pd.DataFrame(data) # 生成事件对及前一行事件对 df['pair'] = list(zip(df['L1'], df['L2'])) df['prev_pair'] = df.groupby('id')['pair'].shift(1) # 判断当前事件是否是前一事件的逆序(循环的一部分) def is_reverse(pair1, pair2): if pd.isna(pair1) or pd.isna(pair2): return False return pair1[0] == pair2[1] and pair1[1] == pair2[0] df['is_cycle'] = df.apply(lambda x: is_reverse(x['prev_pair'], x['pair']), axis=1) # 为连续循环序列分配组号,非循环事件组号重置为0 df['cycle_group'] = df.groupby('id')['is_cycle'].cumsum() df['cycle_group'] = df.groupby('id')['cycle_group'].apply( lambda x: x.where(df.loc[x.index, 'is_cycle'], 0) ) # 统计每个循环组的事件出现次数,筛选次数≥2的记录 count_df = df.groupby(['id', 'pair', 'cycle_group']).size().reset_index(name='count') count_df = count_df[count_df['count'] >= 2] # 拆分事件对为L1、L2列,整理最终结果 count_df[['L1', 'L2']] = pd.DataFrame(count_df['pair'].tolist(), index=count_df.index) result = count_df[['id', 'L1', 'L2', 'count']].sort_values('id').reset_index(drop=True) print(result)
代码说明
- 将
L1和L2组合为事件对pair,并获取分组内的前一事件对prev_pair - 通过
is_reverse函数标记连续循环的事件 - 用
cumsum为连续循环序列分配组号,非循环事件组号重置,确保不同循环序列被区分 - 分组统计次数后,筛选出符合条件的记录并整理成目标格式
内容的提问来源于stack exchange,提问作者python_interest
相关产品推荐
相关产品推荐

