Python如何识别同姓名同日期下冲突≥3次的并发事件
并发事件识别实现方案
核心逻辑
基于pandas向量化运算实现,完全替代循环处理,性能远高于逐行遍历,适配你的规则:同一姓名、同一事件日期下,连续冲突次数≥3判定为并发。
处理流程如下:
- 按「姓名+事件日期」分组,组内所有事件按开始时间升序排序
- 生成冲突标记列:判断当前行与前一行时间是否重叠,重叠则标记为冲突
- 为连续冲突的事件段打统一分组标记,所有连续冲突的行会归属同一个分组
- 统计每个冲突分组的长度,长度≥3的分组标记为并发事件组,回写标记到原数据
完整可运行代码
import pandas as pd # ---------------------- 示例数据构造,可替换为你的实际数据 ---------------------- df = pd.DataFrame({ "姓名": ["张三", "张三", "张三", "张三", "李四", "李四", "李四", "李四"], "事件日期": ["2024-05-01", "2024-05-01", "2024-05-01", "2024-05-02", "2024-05-01", "2024-05-01", "2024-05-01", "2024-05-01"], "开始时间": ["09:00", "09:30", "10:00", "09:00", "08:00", "08:20", "08:40", "09:10"], "结束时间": ["10:00", "10:30", "11:00", "10:00", "09:00", "08:50", "09:20", "09:40"] }) # 时间列转datetime格式,方便比较 df["开始时间"] = pd.to_datetime(df["事件日期"] + " " + df["开始时间"]) df["结束时间"] = pd.to_datetime(df["事件日期"] + " " + df["结束时间"]) # ---------------------- 核心处理逻辑 ---------------------- # 1. 按分组排序,保证时间序列有序 df = df.sort_values(by=["姓名", "事件日期", "开始时间"]).reset_index(drop=True) # 2. 生成逐行冲突标记:当前行开始时间 < 上一行结束时间,即为和上一行冲突 df["is_conflict"] = df.groupby(["姓名", "事件日期"])["开始时间"].shift(1) < df["结束时间"] # 每组第一行无前置行,默认无冲突 df.loc[df.groupby(["姓名", "事件日期"]).head(1).index, "is_conflict"] = False # 3. 为连续冲突段打分组标记 df["conflict_group"] = df.groupby(["姓名", "事件日期"])["is_conflict"].apply( lambda x: (x != x.shift()).cumsum() ) # 4. 筛选满足连续冲突≥3的分组 group_stat = df.groupby(["姓名", "事件日期", "conflict_group", "is_conflict"]).size().reset_index(name="conflict_cnt") # 此处conflict_cnt即为连续冲突次数,按需调整阈值即可 target_groups = group_stat[(group_stat["is_conflict"] == True) & (group_stat["conflict_cnt"] >= 3)] # 5. 回写并发标记到原表 df["is_concurrent"] = df.set_index(["姓名", "事件日期", "conflict_group"]).index.isin( target_groups.set_index(["姓名", "事件日期", "conflict_group"]).index ) # 可选:删除中间过程列 df = df.drop(columns=["is_conflict", "conflict_group"])
备选实现(非连续冲突场景)
如果规则不需要冲突连续,只要同一个人同一天内和当前事件冲突的事件总数≥3就算并发,可直接用区间重叠统计实现:
# 构造时间区间 df["time_interval"] = df.apply(lambda x: pd.Interval(x["开始时间"], x["结束时间"], closed="left"), axis=1) # 统计每个区间的重叠次数 def calc_overlap_count(interval_list): return [sum(iv.overlaps(current_iv) for iv in interval_list) for current_iv in interval_list] df["overlap_count"] = df.groupby(["姓名", "事件日期"])["time_interval"].transform(calc_overlap_count) # 标记并发 df["is_concurrent"] = df["overlap_count"] >= 3
内容的提问来源于stack exchange,提问作者Mystical Me
相关产品推荐
相关产品推荐

