Pandas时序DataFrame按列值筛选:分组保留首个正值后数据
筛选多索引分组Pandas DataFrame:保留首个value>0时间点后的所有数据
咱先来明确需求:给每个id分组,找出每组里时序上第一个value大于0的记录,然后把从这个记录开始往后的所有数据都保留下来。先看你提供的示例(我猜可能输入里第一行的value是笔误,应该是0?不然输出和需求对不上,不过咱先按逻辑来拆解)。
步骤1:准备示例数据
先把你给的输入数据用Pandas构造出来:
import pandas as pd data = { 'id': [1, 1, 1, 1, 1], 'timestamp': ['2001-01-01', '2001-10-01', '2001-10-02', '2001-10-03', '2001-10-04'], 'date': ['2001-05-01']*5, 'value': [1, 0, 1, 0, 1] } df = pd.DataFrame(data) # 先把timestamp转成日期格式,保证时序排序正确 df['timestamp'] = pd.to_datetime(df['timestamp'])
步骤2:核心解决方案
要实现需求,关键是给每个分组标记出哪些行需要保留。这里用groupby + transform + cummax的组合最简洁:
- 先按
id和timestamp排序,确保时序是从早到晚的(这一步非常重要,不然找“第一个”会出错) - 对每个
id分组,生成一个布尔标记:从第一个value>0的位置开始,后面所有行都标记为True - 筛选标记为
True的行,得到结果
代码如下:
# 1. 按id和timestamp排序,保证时序正确 df_sorted = df.sort_values(['id', 'timestamp']) # 2. 生成保留标记:cummax会把第一个True之后的所有元素都保持为True df_sorted['keep'] = df_sorted.groupby('id')['value'].transform(lambda x: (x > 0).cummax()) # 3. 筛选并去掉临时列 result = df_sorted[df_sorted['keep']].drop('keep', axis=1) print(result)
解释为什么用cummax
(x > 0)会给每个分组生成一个布尔数组,比如示例里的分组id=1会得到[True, False, True, False, True]。而cummax()(累积最大值)会把第一个True之后的所有元素都变成True,也就是[True, True, True, True, True]——这时候筛选出来的就是从第一个value>0开始的所有数据。
如果你的示例输入里第一行的value其实是0(这样才符合期望输出),那(x>0)会得到[False, False, True, False, True],cummax()后变成[False, False, True, True, True],筛选出来的就是后三行,和你要的期望输出完全一致。
扩展:如果是多索引的情况
如果你的DataFrame已经是id和timestamp的多索引,那处理逻辑类似,只需要调整分组方式:
# 假设df是多索引,索引为['id', 'timestamp'] df['keep'] = df.groupby(level='id')['value'].transform(lambda x: (x > 0).cummax()) result = df[df['keep']].drop('keep', axis=1)
内容的提问来源于stack exchange,提问作者gustavz
相关产品推荐
相关产品推荐

