如何对DataFrame分组后统计每组连续1的最大数量并映射至全行
解决按组统计连续1的最大次数并映射到每行的问题
这是个很典型的连续序列统计需求,我来一步步带你实现:
首先,先确认输入数据:
import pandas as pd df = pd.DataFrame({ 'A':[1,1,1,1,1,1,2,2,2,2,2,2,2], 'flag':[1,1,0,1,1,1,0,1,1,0,1,1,1] })
步骤1:识别每组内的连续1区块
我们需要在每个A分组内,给连续的1(以及单独的0)分配唯一的区块ID,这样才能统计每个区块的长度:
df['block_id'] = df.groupby('A')['flag'].apply( lambda x: (x != x.shift() | (x == 0)).cumsum() )
这里的逻辑是:
x != x.shift()标记每个连续序列的起始位置(比如从0变1,或者从1变0)| (x == 0)把所有0的位置也单独划成一个区块,避免和后面的1区块混淆cumsum()给每个连续区块分配递增的ID
步骤2:计算每个1区块的长度并取组内最大值
接下来筛选出所有flag=1的区块,统计每个区块的长度,再按A分组取最大值:
# 统计每个1区块的长度 block_lengths = df[df['flag'] == 1].groupby(['A', 'block_id']).size() # 按A分组取最大的连续1长度 max_consec = block_lengths.groupby('A').max().rename('consective_count_max')
步骤3:将最大值映射回原DataFrame的每一行
最后把计算好的最大值合并回原数据,每个A组的所有行都会得到对应的最大值:
output = df[['A']].merge(max_consec, on='A', how='left')
更简洁的写法(用transform一步到位)
如果想简化代码,可以用groupby.transform直接把组内最大值应用到每一行:
def get_max_consec_ones(series): # 生成区块ID blocks = (series != series.shift() | (series == 0)).cumsum() # 计算每个区块长度,筛选出1的区块后取最大值 block_sizes = series.groupby(blocks).size() # 只保留flag为1的区块的长度,再取最大 return block_sizes[series.groupby(blocks).first() == 1].max() # 直接用transform把结果映射到每行 output = df.assign( consective_count_max=df.groupby('A')['flag'].transform(get_max_consec_ones) )[['A', 'consective_count_max']]
运行后得到的output就是你期望的结果:
A consective_count_max 0 1 3 1 1 3 2 1 3 3 1 3 4 1 3 5 1 3 6 2 3 7 2 3 8 2 3 9 2 3 10 2 3 11 2 3 12 2 3
内容的提问来源于stack exchange,提问作者Nickel
相关产品推荐
相关产品推荐

