Pandas:按id和consecBool分组时,遇False重置累加计数器
问题:布尔列值为False时重置分组累加计数器
之前参考的「累计统计True值」方案无法满足需求——该方案默认数据集无独立分组,但实际需要按id和连续的consecBool块进行分组,要求每次consecBool为False时,后续的累加计数器重置。
示例数据与当前错误实现
先看示例数据集和当前错误的代码:
import pandas as pd df = pd.DataFrame({'id': [1, 1, 1, 1, 1, 1, 1], 'consecDays': [0, 1, 1, 1, 0, 1, 1], 'consecBool': [False, True, True, True, False, True, True], 'expected': [0, 1, 2, 3, 0, 1, 2]}) # 当前错误的累加方式 df['Counter'] = df.groupby(['id', 'consecBool'])['consecDays'].cumsum()
执行后得到的Counter列不符合预期,错误结果如下:
id consecDays consecBool expected Counter 0 1 0 False 0 0 1 1 1 True 1 1 2 1 1 True 2 2 3 1 1 True 3 3 4 1 0 False 0 0 5 1 1 True 1 4 6 1 1 True 2 5
可以看到,第5、6行的Counter没有重置,而是继续累加之前True块的数值,这和expected列的要求不符。
正确解决方案
核心思路是:为每个连续的consecBool=True块生成独立的子分组标识,结合id进行累加,最后将consecBool=False的行计数器设为0。
代码实现
# 1. 按id分组,生成连续布尔块的分组标识:每次布尔值切换时,分组ID递增 df['group_id'] = df.groupby('id')['consecBool'].transform( lambda x: x.ne(x.shift()).cumsum() ) # 2. 按id和group_id分组累加consecDays df['Counter'] = df.groupby(['id', 'group_id'])['consecDays'].cumsum() # 3. 将consecBool为False的行Counter设为0 df.loc[~df['consecBool'], 'Counter'] = 0
正确结果
执行后得到符合预期的结果:
id consecDays consecBool expected group_id Counter 0 1 0 False 0 1 0 1 1 1 True 1 2 1 2 1 1 True 2 2 2 3 1 1 True 3 2 3 4 1 0 False 0 3 0 5 1 1 True 1 4 1 6 1 1 True 2 4 2
逻辑说明
group_id的生成:通过x.ne(x.shift())检测当前行和前一行的consecBool是否不同,不同则标记为True,再用cumsum()累加生成唯一的分组ID,这样每个连续的True块会被分到独立的分组中。- 分组累加时,每个独立的True块会单独计算累加值,不会和之前的True块混淆。
- 最后将False对应的行计数器重置为0,完全匹配预期结果。
内容的提问来源于stack exchange,提问作者John Stud
相关产品推荐
相关产品推荐

