按分组统计DataFrame两列中值的首次与二次出现情况
问题描述
现有一个已按Ref1和Seq排序的DataFrame,结构如下:
| Ref1 | EvnNo | P1 | P2 | Seq | PP1 | PP2 |
|---|---|---|---|---|---|---|
| aaaa | 0 | xxx | yyy | 1 | 0 | 1 |
| aaaa | 0 | xxx | yyy | 2 | 0 | 0 |
| aaaa | 0 | xxx | yyy | 3 | 1 | 0 |
| aaaa | 0 | xxx | yyy | 4 | 0 | 0 |
| aaaa | 1 | xxx | yyy | 5 | 0 | 0 |
| aaaa | 1 | xxx | yyy | 6 | 1 | 0 |
| aaaa | 1 | xxx | yyy | 7 | 1 | 0 |
| aaaa | 1 | xxx | yyy | 8 | 0 | 1 |
| bbbb | 0 | xxx | yyy | 1 | 0 | 0 |
| bbbb | 0 | xxx | yyy | 2 | 0 | 0 |
| bbbb | 0 | xxx | yyy | 3 | 0 | 0 |
| bbbb | 0 | xxx | yyy | 4 | 0 | 0 |
| bbbb | 1 | xxx | yyy | 5 | 0 | 0 |
| bbbb | 1 | xxx | yyy | 6 | 0 | 0 |
| bbbb | 1 | xxx | yyy | 7 | 1 | 0 |
| bbbb | 1 | xxx | yyy | 8 | 0 | 1 |
需要完成两项统计任务:
- 按
Ref1和EvNo分组,统计PP1或PP2列中首次出现1的次数(分组内可能无1出现,同一行的PP1和PP2不会同时为1)。 - 若分组内存在1的首次出现,统计首次出现后另一列出现1的情况:比如首次出现的1在
PP1列,则只统计后续PP2列的1;若后续1仍在PP1列则不计入,分组内可能无后续1出现。
预期输出:
| P1 First Occ | P2 First Occ | P1 Second Occ | P2 Second Occ |
|---|---|---|---|
| 2 | 1 | 0 | 1 |
解决方案
可以用Pandas的分组操作结合自定义函数实现需求,代码如下:
import pandas as pd # 构造原始DataFrame data = [ ["aaaa", 0, "xxx", "yyy", 1, 0, 1], ["aaaa", 0, "xxx", "yyy", 2, 0, 0], ["aaaa", 0, "xxx", "yyy", 3, 1, 0], ["aaaa", 0, "xxx", "yyy", 4, 0, 0], ["aaaa", 1, "xxx", "yyy", 5, 0, 0], ["aaaa", 1, "xxx", "yyy", 6, 1, 0], ["aaaa", 1, "xxx", "yyy", 7, 1, 0], ["aaaa", 1, "xxx", "yyy", 8, 0, 1], ["bbbb", 0, "xxx", "yyy", 1, 0, 0], ["bbbb", 0, "xxx", "yyy", 2, 0, 0], ["bbbb", 0, "xxx", "yyy", 3, 0, 0], ["bbbb", 0, "xxx", "yyy", 4, 0, 0], ["bbbb", 1, "xxx", "yyy", 5, 0, 0], ["bbbb", 1, "xxx", "yyy", 6, 0, 0], ["bbbb", 1, "xxx", "yyy", 7, 1, 0], ["bbbb", 1, "xxx", "yyy", 8, 0, 1], ] df = pd.DataFrame(data, columns=["Ref1", "EvnNo", "P1", "P2", "Seq", "PP1", "PP2"]) def analyze_group(group): # 筛选分组内有1的行 has_one = group[(group["PP1"] == 1) | (group["PP2"] == 1)] if has_one.empty: return {"first_p1": 0, "first_p2": 0, "second_p1": 0, "second_p2": 0} # 确定首次出现1的列 first_row = has_one.iloc[0] first_col = "PP1" if first_row["PP1"] == 1 else "PP2" # 统计首次出现类型 first_p1 = 1 if first_col == "PP1" else 0 first_p2 = 1 if first_col == "PP2" else 0 # 筛选首次出现后的行,统计另一列的1数量 after_first = group[group["Seq"] > first_row["Seq"]] target_col = "PP2" if first_col == "PP1" else "PP1" second_count = after_first[after_first[target_col] == 1].shape[0] # 分配到对应统计项 second_p1 = second_count if target_col == "PP1" else 0 second_p2 = second_count if target_col == "PP2" else 0 return {"first_p1": first_p1, "first_p2": first_p2, "second_p1": second_p1, "second_p2": second_p2} # 分组计算并求和,重命名列 result = df.groupby(["Ref1", "EvnNo"]).apply(analyze_group).apply(pd.Series).sum().to_frame().T result.columns = ["P1 First Occ", "P2 First Occ", "P1 Second Occ", "P2 Second Occ"] print(result)
代码说明
- 构造数据:将原始数据转换为Pandas DataFrame。
- 自定义分析函数:
- 先筛选分组内包含1的行,若无则返回全0结果。
- 定位首次出现1的列,标记首次出现的类型。
- 筛选首次出现后的行,只统计另一列中1的数量。
- 分组统计:按
Ref1和EvnNo分组应用函数,对各组结果求和后重命名列,得到最终统计表格。
运行代码后输出与预期一致:
| P1 First Occ | P2 First Occ | P1 Second Occ | P2 Second Occ | |
|---|---|---|---|---|
| 0 | 2 | 1 | 0 | 1 |
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

