
本文介绍如何在 Pandas 中按时间顺序(DateTime)对数据进行排序后,分别计算满足 Tag != 2 和 Tag == 2 条件的累计数量(RBQ 和 RSQ),确保累计逻辑严格遵循时间先后顺序。
本文介绍如何在 pandas 中按时间顺序(datetime)对数据进行排序后,分别计算满足 `tag != 2` 和 `tag == 2` 条件的累计数量(rbq 和 rsq),确保累计逻辑严格遵循时间先后顺序。
在实际数据分析中,常需根据业务规则对不同类别(如标签 Tag)的数据进行独立但有序的累计求和——尤其当累计必须尊重时间先后顺序(而非原始行序)时,直接使用 .cumsum() 会出错。本教程以一个典型场景为例:为每行数据添加两列:
-
RBQ:截至当前行DateTime时刻、所有Tag ≠ 2的历史Qty累计和; -
RSQ:截至当前行DateTime时刻、所有Tag == 2的历史Qty累计和。
关键前提是:累计必须按 DateTime 升序执行,否则结果将不符合业务语义(例如“截至某时刻的累计量”)。
✅ 正确做法:先排序,再条件掩码 + 累计
首先确保 DateTime 列为 datetime 类型并升序排列:
import pandas as pd
# 示例数据(注意:DateTime 需转为 datetime 类型)
df = pd.DataFrame({
'DateTime': ['2025-01-01 13:00', '2025-01-03 13:22', '2025-01-10 12:33',
'2025-01-22 10:04', '2025-01-29 09:30', '2025-02-02 15:05'],
'Tag': [1, 1, 2, 2, 3, 1],
'Qty': [270, 32, 44, 120, 182, 216]
})
df['DateTime'] = pd.to_datetime(df['DateTime'])然后执行核心逻辑(推荐方案,简洁高效):
# 按 DateTime 排序(关键!)
df_sorted = df.sort_values('DateTime').reset_index(drop=True)
# 定义条件:Tag == 2
cond = df_sorted['Tag'] == 2
# RBQ:仅累加 Tag ≠ 2 的 Qty(Tag==2 时置 0)
df_sorted['RBQ'] = df_sorted['Qty'].mask(cond, 0).cumsum()
# RSQ:仅累加 Tag == 2 的 Qty(Tag≠2 时置 0)
df_sorted['RSQ'] = df_sorted['Qty'].where(cond, 0).cumsum()
print(df_sorted[['DateTime', 'Tag', 'Qty', 'RBQ', 'RSQ']])输出结果完全匹配预期:
DateTime Tag Qty RBQ RSQ 0 2025-01-01 13:00:00 1 270 270.0 0.0 1 2025-01-03 13:22:00 1 32 302.0 0.0 2 2025-01-10 12:33:00 2 44 302.0 44.0 3 2025-01-22 10:04:00 2 120 302.0 164.0 4 2025-01-29 09:30:00 3 182 484.0 164.0 5 2025-02-02 15:05:00 1 216 700.0 164.0
⚠️ 注意事项:
- 务必先
sort_values('DateTime'):原始索引顺序不反映时间逻辑,忽略此步会导致累计错误;mask(cond, 0)表示「满足条件则替换为 0」,where(cond, 0)表示「满足条件才保留原值,否则填 0」;.cumsum()是向量化操作,性能远优于apply或循环,且天然保持排序后顺序;- 若需保留原始行序(如后续需 merge 回原表),可先保存原始索引,排序处理后再按原索引还原。
? 进阶技巧:使用 pivot 实现多条件累计(可扩展性强)
当条件维度增多(如需按 Tag 多个取值分别累计),可借助 pivot 构建宽表后累计:
# 构造分组标识列
df_pivot = df_sorted.assign(
group_col=df_sorted['Tag'].eq(2).map({True: 'RSQ', False: 'RBQ'})
)
# 转为宽表 → 填充缺失 → 累计 → 合并回原表
cumulative = (df_pivot.pivot(columns='group_col', values='Qty')
.fillna(0)
.cumsum()
.reset_index(drop=True))
df_sorted = pd.concat([df_sorted, cumulative], axis=1)该方法更易扩展至多个标签(如 Tag in [1,2,3]),只需调整 group_col 映射逻辑即可。
✅ 总结
- 条件累计的核心是 「排序 + 条件屏蔽 + 向量化累计」 三步组合;
-
mask/where提供了灵活的条件值替换能力,比布尔索引赋值更简洁安全; - 所有操作均应作用于按时间排序后的 DataFrame,这是保证业务正确性的前提;
- 对于复杂分组需求,
pivot+cumsum方案具备良好可维护性与可读性。
掌握这一模式,即可轻松应对各类基于时间线与分类标签的动态累计分析任务。

















