Pandas如何基于其他列与前序行值重排DataFrame列序号
pandas按事件段重编号day列实现方案
原始数据与需求
原始DataFrame结构如下:
date day_of_week day 2021-01-01 3 1 2021-01-02 4 2 2021-01-03 5 0 2021-01-04 6 1 2021-01-05 7 2 2021-01-06 1 3 2021-01-07 2 0 2021-01-08 3 0
编号规则:
- 识别所有连续
day>0的行组成独立事件段,day=0为段分隔符,值保持0不变 - 每个事件段根据段首行的
day_of_week值确定编号起始基数:- 段首
day_of_week < 4(周四前起始):段内非0day值从20开始依次递增 - 段首
day_of_week >= 4(周四及之后起始):段内非0day值从30开始依次递增
目标输出结果:
- 段首
date day_of_week day 2021-01-01 3 20 2021-01-02 4 21 2021-01-03 5 0 2021-01-04 6 30 2021-01-05 7 31 2021-01-06 1 32 2021-01-07 2 0 2021-01-08 3 0
实现代码
不需要逐行遍历,用pandas连续值分组+向量化运算即可高效实现:
import pandas as pd import numpy as np # 1. 构造原始测试数据 df = pd.DataFrame({ 'date': ['2021-01-01','2021-01-02','2021-01-03','2021-01-04','2021-01-05','2021-01-06','2021-01-07','2021-01-08'], 'day_of_week': [3,4,5,6,7,1,2,3], 'day': [1,2,0,1,2,3,0,0] }) # 2. 标记连续事件段:遇到day=0则事件id递增 df['event_id'] = (df['day'] == 0).cumsum() non_zero_mask = df['day'] > 0 # 3. 匹配每个事件段的编号起始基数 base_config = df[non_zero_mask].groupby('event_id')['day_of_week'].first().apply( lambda x: 20 if x < 4 else 30 ) df['base_num'] = df['event_id'].map(base_config) # 4. 段内递增生成新编号,0值保持不变 df.loc[non_zero_mask, 'day'] = df[non_zero_mask].groupby('event_id').cumcount() + df.loc[non_zero_mask, 'base_num'] df['day'] = df['day'].fillna(0).astype(int) # 5. 删除临时列 df = df.drop(columns=['event_id', 'base_num'])
运行后打印df即可得到目标结果。
注:该实现为pandas原生向量化写法,运行效率远高于逐行遍历,十万级以上数据量下性能差距尤为明显。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

