如何用Pythonic方式在Pandas中按组检测数据超3%增长并标记
Pandas实现分组内值超3%增长的标记方案
给定如下结构的数据集:
Id date value x1 01-01-22 46 x1 02-01-22 46 x1 03-01-22 45.8 .... x2 03-04-22 57 X2 03-04-22 62 ....
需求是:每个Id组内的value需随时间保持递减或不变(允许少量测量误差),新增一列标记当value较同组前一个时间点的值增长超过3%时为1,否则为0,同时要处理Id大小写不一致的问题(如x2和X2属于同一分组)。
解决方案
1. 数据预处理
先统一Id的大小写,避免分组错误;同时将date转换为日期格式并按Id和date排序,确保数据按时间顺序排列:
import pandas as pd # 假设数据已加载到DataFrame df中 df['Id'] = df['Id'].str.lower() df['date'] = pd.to_datetime(df['date'], format='%d-%m-%y') df = df.sort_values(['Id', 'date']).reset_index(drop=True)
2. 分组生成标记列
使用groupby结合transform方法,链式完成增长比例计算与标记列生成,这是最Pythonic的写法:
df['is_invalid'] = df.groupby('Id')['value'].transform( lambda g: (g / g.shift(1) > 1.03).astype(int) )
如果喜欢更连贯的链式操作,可以把预处理和标记生成整合在一起:
df = (df .assign(Id=lambda x: x['Id'].str.lower(), date=lambda x: pd.to_datetime(x['date'], format='%d-%m-%y')) .sort_values(['Id', 'date']) .assign(is_invalid=lambda x: x.groupby('Id')['value'] .transform(lambda g: (g / g.shift(1) > 1.03).astype(int))) .reset_index(drop=True) )
关键逻辑说明
shift(1):获取同组前一行的value值,用于计算增长比例g / g.shift(1) > 1.03:判断当前值较前值的增长幅度是否超过3%astype(int):将布尔判断结果转换为1(符合条件)或0(不符合条件)transform方法直接返回与原DataFrame长度匹配的结果,无需额外处理索引,写法简洁优雅
内容的提问来源于stack exchange,提问作者user1357015
相关产品推荐
相关产品推荐

