基于Pandas DataFrame计算事件连续时段时长并标记首行
问题需求
我有一个包含id、条件指示器列target和时间戳列time的DataFrame,需要按id分组实现以下逻辑:
- 当
target为True时,统计连续True的时段数量(即分段数)作为时长 - 仅在连续
True时段的首行标记该时长,后续True行及所有False行均标记为0
补充说明:数据按5分钟固定分段,时长直接统计连续True的分段数,无需通过时间差计算。以B组为例:
11:00时target为True,11:05时仍为True → 11:00行duration标记为2,11:05行标记为0;
11:10时target为False,计数重置;
11:15时target为True,11:20时仍为True → 11:15行duration标记为2,11:20行标记为0;
B组最终duration值应为[2,0,0,2,0,0]
示例数据
import pandas as pd time_test = pd.DataFrame({'id':[ 'A','B','C','A','B','C', 'A','B','C','A','B','C', 'A','B','C','A','B','C'], 'target':[ 'True','True','True','False','True','True', 'True','False','True','True','True','True', 'False','True','False','True','False','True'], 'time':[ '11:00','11:00','11:00','11:05','11:05','11:05', '11:10','11:10','11:10','11:15','11:15','11:15', '11:20','11:20','11:20','11:25','11:25','11:25']}) time_test = time_test.sort_values(['id','time']) time_test['time'] = pd.to_datetime(time_test['time']) # 转换target为布尔值,方便后续逻辑处理 time_test['target'] = time_test['target'].map({'True': True, 'False': False})
实现步骤
步骤1:标记连续True的分组
按id分组后,用~target的累积求和来区分不同的连续True分段:
# 生成分组标识:每次遇到False,分组号递增,以此隔离不同的连续True段 time_test['group_id'] = time_test.groupby('id')['target'].apply( lambda x: (~x).cumsum() )
步骤2:统计每组的连续分段数
按id和group_id分组,统计每组的行数(即连续分段的数量),并合并回原DataFrame:
# 计算每个连续True组的长度 group_length = time_test.groupby(['id', 'group_id'])['target'].count().reset_index(name='duration') # 将统计结果匹配到原表对应行 time_test = time_test.merge(group_length, on=['id', 'group_id'], how='left')
步骤3:仅保留首行的时长值
标记每组的首行,仅在首行且target为True时保留统计的时长,其余行设为0:
# 标记当前行是否为所在分组的首行 time_test['is_first'] = time_test.groupby(['id', 'group_id']).cumcount() == 0 # 按规则设置duration值 time_test['duration'] = time_test.apply( lambda row: row['duration'] if row['is_first'] and row['target'] else 0, axis=1 ) # 清理中间辅助列 time_test = time_test.drop(['group_id', 'is_first'], axis=1)
验证结果
查看B组的输出:
print(time_test[time_test['id'] == 'B'])
输出符合预期:
id target time duration 1 B True 2023-10-17 11:00:00 2 4 B True 2023-10-17 11:05:00 0 7 B False 2023-10-17 11:10:00 0 10 B True 2023-10-17 11:15:00 2 13 B True 2023-10-17 11:20:00 0 16 B False 2023-10-17 11:25:00 0
内容的提问来源于stack exchange,提问作者Rebecca James
相关产品推荐
相关产品推荐

