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

在Pandas DataFrame中按ID分组提取连续0的中间行及后续首个1行

解决Pandas按ID分组提取特定模式行的问题

没问题,我来帮你搞定这个需求!咱们要做的是按id分组,找出每组里连续至少5个0,且后面紧跟着1的序列,然后提取这些连续0的中间行,以及后续第一个1的行。下面一步步来:

1. 准备示例数据

先创建一个带id、event和其他列的示例DataFrame,方便咱们演示:

import pandas as pd
import numpy as np

# 构造示例数据
data = {
    'id': [1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2],
    'event': [0,0,0,0,0,1,0,0,0,0, 0,0,0,0,0,0,1,0,0,1,0],
    'other_col': np.arange(1,22)
}
df = pd.DataFrame(data)

这个示例里,id=1有一段5个0后跟1,还有一段4个0(不符合≥5的条件);id=2有一段6个0后跟1,还有一段2个0后跟1(不符合)。

2. 分组标记连续块并筛选符合条件的序列

接下来咱们要给每个分组内的行标记所属的连续块,然后筛选出符合要求的块:

def process_group(group):
    # 标记event是否为0
    is_zero = group['event'] == 0
    # 标记连续0块的起始点:当前是0且前一行不是0(或者是第一行)
    block_start = is_zero & (~is_zero.shift(fill_value=False))
    # 给每个连续块分配唯一ID
    group['block_id'] = block_start.cumsum()
    # 只保留0的块,然后计算每个块的长度
    zero_blocks = group[is_zero].groupby('block_id').size().reset_index(name='block_length')
    # 筛选出长度≥5的0块
    valid_zero_blocks = zero_blocks[zero_blocks['block_length'] >=5]['block_id'].tolist()
    
    result_rows = []
    for block_id in valid_zero_blocks:
        # 获取当前0块的所有行
        block_rows = group[group['block_id'] == block_id]
        # 检查块后面是否紧跟1:块的最后一行的下一行event是1
        last_block_idx = block_rows.index[-1]
        if last_block_idx +1 >= len(group):
            # 块在分组末尾,后面没有行,跳过
            continue
        next_row = group.iloc[last_block_idx +1]
        if next_row['event'] !=1:
            continue
        
        # 提取0块的中间行:长度n,中间位置是(n-1)//2(索引从0开始)
        n = len(block_rows)
        middle_idx_in_block = (n-1)//2
        middle_row = block_rows.iloc[middle_idx_in_block]
        result_rows.append(middle_row)
        # 提取后面的第一个1行
        result_rows.append(next_row)
    
    return pd.DataFrame(result_rows) if result_rows else pd.DataFrame(columns=group.columns)

# 应用分组处理
final_result = df.groupby('id').apply(process_group).reset_index(drop=True)

3. 查看结果

运行上面的代码后,final_result就是咱们要的结果:

print(final_result)

输出大概是这样(对应示例数据):

id  event  other_col  block_id
0    1      0          3         1
1    1      1          6         0
2    2      0          8         1
3    2      1         13         0

解释一下:

  • id=1的5个0中间行是第3个0(other_col=3),后面的1是other_col=6的行;
  • id=2的6个0中间行是第3个0(other_col=8),后面的1是other_col=13的行。

一些补充说明

  • 如果连续0的长度是偶数(比如6),这里取的是第(n-1)//2个,也就是索引2(第3个元素),你也可以根据需求改成取中间两个的任意一个,比如n//2;
  • 代码里已经处理了块在分组末尾后面没有行的情况,以及块后面不是1的情况,这些都会被跳过;
  • 如果同一个id里有多个符合条件的块,都会被提取出来。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:20:52