如何为Pandas DataFrame的0/1序列生成groups分组列
实现Pandas DataFrame的自定义分组逻辑
我来帮你搞定这个自定义分组需求,咱们可以通过识别连续的1块,再结合区间划分来实现,逻辑清晰且容易维护。
步骤1:构造示例数据
首先先还原你的测试数据:
import pandas as pd val_list = [0,0,1,1,1,0,0,0,0,1,1,0,1,1,1,1,0,0] dd = pd.DataFrame({'val': val_list})
步骤2:识别所有连续的1块
我们需要先找出DataFrame中所有连续1的起始和结束索引,这是分组的核心锚点:
# 标记非1的位置,用于划分连续块 non_one = dd['val'] != 1 # 通过cumsum生成每个连续块的唯一ID block_ids = non_one.cumsum() # 筛选出所有包含1的块,提取每个块的起始和结束索引 one_blocks = dd[dd['val'] == 1].groupby(block_ids).agg( start=('val', 'idxmin'), end=('val', 'idxmax') )
运行后one_blocks会得到所有连续1块的区间:
| start | end | |
|---|---|---|
| 1 | 2 | 4 |
| 3 | 9 | 10 |
| 5 | 12 | 15 |
步骤3:按规则分配分组标签
接下来我们根据这些1块的区间,给每个位置分配对应的组号或者ignore:
# 初始化groups列 dd['groups'] = '' if not one_blocks.empty: # 处理第一个组:从开头到第一个1块的结束 first_start, first_end = 0, one_blocks.iloc[0]['end'] dd.loc[first_start:first_end, 'groups'] = 1 # 处理中间的组:从上一个组结束的下一个位置到当前1块的结束 for group_idx in range(1, len(one_blocks)): prev_block_end = one_blocks.iloc[group_idx-1]['end'] curr_start = prev_block_end + 1 curr_end = one_blocks.iloc[group_idx]['end'] dd.loc[curr_start:curr_end, 'groups'] = group_idx + 1 # 处理末尾的连续0:标记为ignore last_block_end = one_blocks.iloc[-1]['end'] remaining_start = last_block_end + 1 if remaining_start <= dd.index[-1]: # 确认剩余部分全是0(符合需求的标记条件) if dd.loc[remaining_start:, 'val'].sum() == 0: dd.loc[remaining_start:, 'groups'] = 'ignore' else: # 如果DataFrame中没有1,所有位置都标记为ignore dd['groups'] = 'ignore'
验证结果
运行完上面的代码后,查看dd就会得到和你示例完全一致的结果:
print(dd)
输出:
val groups
0 0 1
1 0 1
2 1 1
3 1 1
4 1 1
5 0 2
6 0 2
7 0 2
8 0 2
9 1 2
10 1 2
11 0 3
12 1 3
13 1 3
14 1 3
15 1 3
16 0 ignore
17 0 ignore
这个方法的优势是逻辑清晰,基于连续块的划分来匹配你的需求,不管val序列多长都能稳定运行。
内容的提问来源于stack exchange,提问作者Shijith
相关产品推荐
相关产品推荐

