如何在Pandas DataFrame中按条件重置累计计数并生成正负天数序列
Pandas按ID分组结合Reset字段生成累计正负天数多列实现方案
核心需求
- 按
id列分组计算日期间隔累计天数,reset字段值为Y时重置计数 - 每个重置分组对应单独的
tdelta#列,重置点前日期标注负天数,重置点后标注正天数 - 单个
id仅含一个重置分组时,无需填充额外的tdelta#列
现有问题
你当前的代码已经完成了基础分组、正序/倒序累计天数计算,但遍历生成tdelta#列时仅能填充当前分组内的正数值,无法覆盖同一个id下重置点之前的行并填充负天数。
优化实现思路
不需要依赖已经计算好的tdelta和tdelta reverse字段,直接以每个id下的reset=Y的日期为锚点,计算同一个id下所有行与锚点的日期差,直接生成对应tdelta#列即可,逻辑更简洁,也能同时覆盖正负值的需求。
完整修正代码
import pandas as pd import numpy as np df = pd.DataFrame({'reset':['N','N','Y','N','N','Y','Y','Y','Y','Y', 'Y'], 'category':['low','low','low','low','low','medium','high','high','medium','medium', 'medium'], 'date':['2019-09-04','2019-09-05','2019-09-06','2019-09-07','2019-09-08','2021-05-23','2021-05-23','2021-05-23','2021-05-23','2021-05-23', '2021-05-22'], 'id':[16860,16860,16860,16860,16860,17611,23409,21765,19480,9166, 9166] }) df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d') df = df.sort_values(['id','date']).reset_index(drop=True) # 生成重置分组标识 df['group'] = df['reset'].replace({'N':False,'Y':True}) df['group'] = df.groupby('id')['group'].cumsum() # 获取每个id+分组对应的重置锚点日期(reset=Y的日期) anchor_map = df[df['reset'] == 'Y'].groupby(['id', 'group'])['date'].first().to_dict() # 遍历每个锚点生成对应tdelta列 for (curr_id, curr_group), anchor_date in anchor_map.items(): col = f'tdelta{int(curr_group)}' # 同一id下所有行计算与当前锚点的日期差 df.loc[df['id'] == curr_id, col] = (df['date'] - anchor_date).dt.days # 过滤仅含一个分组的id,删除其全空tdelta列 id_group_count = df.groupby('id')['group'].nunique() single_group_ids = id_group_count[id_group_count == 1].index for col in df.columns: if col.startswith('tdelta') and col not in ['group']: df.loc[df['id'].isin(single_group_ids), col] = pd.NA df = df.dropna(axis=1, how='all') print(df)
输出效果说明
运行上述代码后,id=16860会生成tdelta1、tdelta2两列,其他仅单次重置的id不会生成多余的tdelta列,完全匹配你给出的预期格式要求。
内容的提问来源于stack exchange,提问作者Ze0ruso
相关产品推荐
相关产品推荐

