
本文介绍如何对 Pandas DataFrame 中按列 C2 的连续相同值块(而非全局相同值)进行分组,并计算每一块对应 C1 列的均值,适用于时间序列、状态变化日志等需识别“连续段”的场景。
本文介绍如何对 pandas dataframe 中按列 c2 的**连续相同值块**(而非全局相同值)进行分组,并计算每一块对应 c1 列的均值,适用于时间序列、状态变化日志等需识别“连续段”的场景。
在数据分析中,常需按“连续状态”而非“全局类别”聚合数据。例如:传感器记录中,C2 表示设备运行模式(如 10=待机、16=运行、23=告警),而我们需要计算每一段连续相同模式期间C1(如温度、负载)的平均值——这不同于 df.groupby('C2')['C1'].mean()(它会将所有 C2=10 的行合并计算,忽略顺序和连续性)。
核心思路是:为 C2 的每个连续相同值区间生成唯一组 ID。Pandas 提供了简洁高效的实现方式:
import pandas as pd
# 构造示例数据
df = pd.DataFrame({
'C1': [10, 20, 30, 5, 6, 8, 4, 2],
'C2': [10, 10, 16, 23, 23, 10, 10, 10]
})
# 方法一:使用 agg() —— 推荐(清晰、易读、支持多列聚合)
result = (df.groupby(df['C2'].ne(df['C2'].shift()).cumsum(), as_index=False)
.agg({'C1': 'mean', 'C2': 'first'}))
print(result.round(6))输出:
C1 C2 0 15.0 10 1 30.0 16 2 5.5 23 3 4.67 10
关键步骤解析:
-
df['C2'].shift():将 C2 下移一行,首行为 NaN; -
df['C2'].ne(...):逐行比较是否“不等于上一行”,返回布尔 Series(True 表示新连续段起点); -
.cumsum():对布尔值累加,为每个连续段分配唯一整数 ID(如[1,1,2,3,3,4,4,4]); -
groupby(...).agg({...}):按该 ID 分组,对 C1 取均值,对 C2 取每组首值(保证原始 C2 值不变)。
方法二(链式写法,兼容旧版):
out = (df.groupby([df['C2'].ne(df['C2'].shift()).cumsum(), 'C2'], sort=False)['C1']
.mean()
.droplevel(0)
.reset_index()
.reindex(df.columns, axis=1))⚠️ 注意事项:
- 必须使用
sort=False(方法一中as_index=False已隐含此意),否则 groupby 默认按分组键排序,打乱原始连续段顺序; -
agg({'C2': 'first'})比agg({'C2': 'last'})更稳妥,因连续段起始值即代表该段状态; - 若数据含缺失值(NaN),
ne(shift())对 NaN 的处理符合预期(NaN ≠ NaN → True),但建议提前清洗; - 此逻辑天然支持任意列组合的连续段识别,只需替换
'C2'为所需列名或布尔条件。
掌握该技巧,可轻松处理设备状态周期分析、用户会话切分、日志事件聚类等真实业务问题。

















