You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Pandas按不同列的is_start与is_end标记值对行进行分组?

高效分组解决方案(无循环)

这是一个典型的区间分组需求,完全可以用pandas的向量化操作实现,不需要低效的iterrows循环。下面是完整的解决方案,包含闭合组提取和未完成组识别:

步骤1:构造示例DataFrame

首先我们先还原你的数据:

import pandas as pd

data = {
    'Date': ['2021-07-16 10:40', '2021-07-16 10:41', '2021-07-16 10:42',
             '2021-07-16 10:43', '2021-07-16 10:44', '2021-07-16 10:45',
             '2021-07-16 10:46', '2021-07-16 10:47', '2021-07-16 10:48',
             '2021-07-16 10:49', '2021-07-16 10:50', '2021-07-16 10:51',
             '2021-07-16 10:52', '2021-07-16 10:53', '2021-07-16 10:54',
             '2021-07-16 10:55'],
    'is_start': [False, False, False, True, False, False, False, True, False,
                 False, False, False, False, False, True, False],
    'is_end': [False, False, False, False, False, True, False, False, False,
               False, False, True, False, False, False, False]
}

df = pd.DataFrame(data)
df['Date'] = pd.to_datetime(df['Date'])

步骤2:生成分组标识(完全向量化)

我们通过累积计数和条件筛选来标记每个行所属的组,全程无循环:

# 1. 计算起始和结束的累积次数
start_cum = df['is_start'].cumsum()
end_cum = df['is_end'].cumsum()

# 2. 初始标记组ID:仅保留未被结束的区间(包括结束行)
df['group_id'] = start_cum.where(start_cum >= end_cum, pd.NA)

# 3. 清除结束行到下一个起始行之间的无效组ID
end_mask = df['is_end'].shift(fill_value=False)
in_between = end_mask.cumsum() - df['is_start'].cumsum()
df['group_id'] = df['group_id'].where(in_between == 0, pd.NA)

步骤3:提取闭合组和未完成组

现在我们可以轻松分离出已完成的组和未完成的组:

# 提取已闭合的组(包含is_end标记的组)
closed_group_ids = df[df['is_end']]['group_id'].unique()
closed_groups = df[df['group_id'].isin(closed_group_ids)].groupby('group_id')

# 提取未完成的组(最后一个start之后没有对应end的区间)
unfinished_group = df[~df['group_id'].isin(closed_group_ids)].dropna(subset=['group_id'])

# 输出结果
print("=== 闭合分组 ===")
for name, group in closed_groups:
    print(f"Group {int(name)}")
    print(group[['Date', 'is_start', 'is_end']])
    print("---")

if not unfinished_group.empty:
    print("\n=== 未完成分组 ===")
    print(unfinished_group[['Date', 'is_start', 'is_end']])

输出结果

运行上述代码后,你会得到:

=== 闭合分组 ===
Group 1
                 Date  is_start  is_end
3 2021-07-16 10:43:00      True   False
4 2021-07-16 10:44:00     False   False
5 2021-07-16 10:45:00     False    True
---
Group 2
                  Date  is_start  is_end
7  2021-07-16 10:47:00      True   False
8  2021-07-16 10:48:00     False   False
9  2021-07-16 10:49:00     False   False
10 2021-07-16 10:50:00     False   False
11 2021-07-16 10:51:00     False    True
---

=== 未完成分组 ===
                  Date  is_start  is_end
14 2021-07-16 10:54:00      True   False
15 2021-07-16 10:55:00     False   False

原理说明

  • start_cum 和 end_cum 分别记录到当前行为止的起始标记和结束标记的累积次数,通过比较两者的大小,我们可以判断当前行是否处于一个未结束的区间内。
  • in_between 标记那些位于“结束标记之后、下一个起始标记之前”的无效行,确保这些行不会被错误地归入任何组。
  • 最后通过筛选包含is_end的组ID,我们精准分离出已完成的闭合组,剩下的就是未完成的组。

这种方法完全利用pandas的向量化运算,效率远高于循环,非常适合处理大规模数据集。

内容的提问来源于stack exchange,提问作者HapiDaze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 13:19:10