df.cumsum()默认按列(axis=0)自上而下累加,遇NaN即中断并污染后续结果;按行累加需显式指定axis=1;groupby后cumsum按组内原始顺序独立计算,不跨组延续。

cumsum 在 DataFrame 中按列累加的默认行为
调用 cumsum() 时,Pandas 默认沿索引方向(axis=0)逐行累加,即对每一列独立做累计和。这不是“整表从左到右”或“按行累加”,而是列内自上而下累积。
常见误判:把 df.cumsum() 当成类似 Excel 的“横向累加”,结果发现每列输出都像在自己内部计数,和预期不符。
- 若想按行累加(即每行内从左到右累计),必须显式指定
axis=1 - 空值(
NaN)会中断当前列的累加链:遇到第一个NaN后,该列后续所有结果均为NaN,不会跳过继续算 - 数据类型需支持加法运算;若某列为字符串,
cumsum()会尝试拼接(如['a','b','c'] → ['a', 'ab', 'abc']),但多数场景应避免
处理含缺失值的 cumsum 结果
cumsum() 对 NaN 非常敏感——它不跳过,而是“污染”后续全部结果。比如第 3 行某列为 NaN,则该列第 3 行及以下所有累计值都是 NaN,即使后面有有效数字。
解决办法不是先 fillna 再 cumsum(会扭曲原始含义),而是用 ffill + mask 组合保留逻辑:
df_filled = df.fillna(0) cumsum_result = df_filled.cumsum()
但更稳妥的做法是明确意图:
- 若
NaN代表“无数据,不应参与累计”,就先用df.mask(df.isna(), 0)替换为 0 再 cumsum - 若
NaN代表“该时刻未发生,累计应暂停”,则保持原样,接受其导致的截断效果 - 注意:浮点型列中
NaN和None行为一致,但整数列含NaN会自动转为float64,这是 Pandas 类型推断机制,不是 bug
cumsum 与 groupby 联合使用的关键限制
在分组后调用 cumsum(),比如 df.groupby('category').value.cumsum(),它默认按 group 内原始顺序累加,**不重置索引也不排序**。这意味着:
- 如果原始数据未按时间/序号排序,分组内的累计顺序可能错乱
- groupby.cumsum() 返回的是
Series,索引与原df对齐,可直接赋值回新列,无需 merge - 不能直接在
agg()中嵌套cumsum,因为cumsum是窗口操作,不是聚合函数;写成.agg({'value': 'cumsum'})会报错Function does not reduce - 跨组连续累加?不行。每个组内独立从头开始,组间不延续
性能差异:cumsum vs 手写循环 vs numpy.cumsum
纯 Python 循环实现累加比 cumsum() 慢 2–3 个数量级,尤其在 >10k 行时明显卡顿;numpy.cumsum() 在单列场景下略快于 Pandas 版本(约 5–10%),但损失了 index 对齐、dtype 自动处理等便利性。
真正影响性能的其实是链式操作中的隐式拷贝:
- 避免
df[['A','B']].cumsum().assign(C=lambda x: x.A + x.B)这类多次视图/副本操作 - 大数据量时,优先用
df.loc[:, ['A','B']].cumsum()显式切片,比布尔索引更快 - 如果只需求某列结果,不要对整个 DataFrame 调用
cumsum(),哪怕其他列是 int8 —— Pandas 仍会为所有列分配临时内存
边界情况容易被忽略:当列名含空格或特殊字符时,df.col_name.cumsum() 失效,必须用 df['col name'].cumsum();另外,cumsum() 不支持 skipna=False 参数(不像 sum()),这个开关不存在。

















