
本文介绍如何为 dataframe 中连续出现的相同值批量标注其所在“块”的长度,即对每个连续重复段内的所有行赋予该段的总出现次数,而非全局统计或简单 groupby。
本文介绍如何为 dataframe 中连续出现的相同值批量标注其所在“块”的长度,即对每个连续重复段内的所有行赋予该段的总出现次数,而非全局统计或简单 groupby。
在数据分析中,常需识别并量化连续重复序列(consecutive runs),例如日志中的状态持续时长、传感器数据中的稳定区间,或交易序列中的连续涨跌。此时,简单的 groupby('Value').transform('size') 会将所有相同值归为一组,无法区分“0,0,0,1,1,0”中首尾两个独立的 0 段——而这正是本问题的关键:需按相邻连续性分组,而非按值本身分组。
核心思路是构造一个能标识“新批次开始”的布尔序列,再通过累加生成唯一组 ID:
- df['Value'].shift() 将列下移一行,使当前行与上一行对齐;
- df['Value'].ne(...) 判断当前值是否不等于前一行值,返回 True 表示“新批次起始”(如索引 0 或值切换处);
- .cumsum() 对该布尔序列累加,自然形成递增的批次编号(如 [1,1,1,2,2,3]),每个连续段拥有唯一 ID。
最终,以此 ID 为键分组,并用 transform('size') 将每组长度广播至组内所有行。
import pandas as pd
# 构建示例数据(注意:原问题末尾多出一个 0,此处按答案逻辑使用 6 行)
df = pd.DataFrame({'Value': [0, 0, 0, 1, 1, 0]})
# 生成连续批次分组标签并计算频次
df['Freq'] = df.groupby(
df['Value'].ne(df['Value'].shift()).cumsum()
)['Value'].transform('size')
print(df)
输出:
Value Freq 0 0 3 1 0 3 2 0 3 3 1 2 4 1 2 5 0 1
✅ 注意事项:
- shift() 默认 periods=1 且 fill_value=None,首行比较结果为 True(因 NaN != 0),恰使其成为首个批次起点;
- 若数据含 NaN,需预先处理(如 fillna() 或改用 diff().ne(0) 等更稳健逻辑);
- 此方法时间复杂度为 O(n),适用于百万级数据,远优于循环实现。
该技巧是 Pandas “连续序列分析”的基石,可延伸用于标记最长连续段、计算连续长度、提取首尾位置等场景。











