基于Pandas按天及列值阈值拆分DataFrame并计算时长与均值
优雅实现:Pandas原生方案处理按天拆分+连续数据块计算
嘿,这个需求完全可以用Pandas的原生分组、标记和聚合操作来搞定,不用依赖循环或者itertools.groupby,代码简洁又高效,我给你一步步拆解:
1. 先构造示例数据(方便你测试)
首先我们先模拟一个符合你描述的DataFrame,时间戳为索引,包含两列:
import pandas as pd import numpy as np # 生成时间戳索引(每15分钟一条数据) timestamps = pd.date_range('2024-01-01 00:00', periods=100, freq='15T') df = pd.DataFrame({ 'col1': np.random.randint(50, 100, size=100), # 随机数值 'col2': np.random.randint(60, 80, size=100) # 包含低于70的数值,用于测试连续块 }, index=timestamps) # 手动插入一些不满足col2≥70的行,模拟非连续的情况 df.loc[df.index[10:15], 'col2'] = 65 df.loc[df.index[30:35], 'col2'] = 62
2. 核心实现步骤
步骤1:标记连续满足条件的数据块
我们用布尔值累加的方式,给每个连续的col2≥70的数据块分配唯一ID:
# 当col2<70时,布尔值为True(即1),累加后会给每个连续满足条件的块分配相同ID df['block_id'] = (df['col2'] < 70).cumsum()
原理:每次遇到不满足条件的行,block_id就会加1,这样连续满足条件的行就会共享同一个block_id,完美区分开不同的连续数据块。
步骤2:按日期+数据块分组,计算目标指标
先过滤出col2≥70的行,然后按日期(从索引提取)和block_id分组,最后聚合计算时长和col1平均值:
# 分组聚合:计算每个连续块的时长和col1均值 result = df[df['col2'] >= 70].groupby([df.index.date, 'block_id']).agg( # 时长:索引的最大时间 - 最小时间 duration=('index', lambda x: x.max() - x.min()), # col1平均值:直接用mean聚合 col1_mean=('col1', 'mean') ).reset_index() # 可选:如果不需要block_id列,可以删除 result = result.drop(columns='block_id')
3. 结果说明
最终的resultDataFrame会包含三列:
index:数据块所属的日期duration:该连续数据块的时长(Timedelta类型,比如0 days 01:15:00)col1_mean:该数据块中col1的平均值
如果某个连续块只有一行数据,时长会显示为0 days 00:00:00,这符合逻辑(单个时间点没有时长)。
内容的提问来源于stack exchange,提问作者Joost




