Python中使用DataFrame.cumsum()时如何忽略首行shift(1)的NaN
解决DataFrame首行shift(1)产生NaN的问题
这问题我之前处理过,确实是shift(1)在首行因为没有上一行数据,必然返回NaN,结合你的水印跟踪需求,给你几个实用的解决方案:
方法一:用fillna()给NaN设置初始值
最直接的方式是给shift(1)后的结果填充一个符合业务逻辑的初始值(比如0,或者首行的cumsum值)。假设你的条件列是cond,代码示例如下:
import pandas as pd import numpy as np # 构造示例数据 df = pd.DataFrame({'tbid': [15, 25, 35, 45], 'cond': [False, True, False, True]}) # 先计算基础的cumsum tbid_cumsum = df['tbid'].cumsum() # 用np.where判断条件,同时给shift后的NaN填充初始值(这里用0,你可以根据业务调整) df['Accum_tbid'] = np.where( df['cond'], tbid_cumsum, tbid_cumsum.shift(1).fillna(0) # 首行NaN替换为0 )
如果你的业务逻辑要求首行即使不满足条件,也等于首行的cumsum值,只需要把fillna(0)改成fillna(tbid_cumsum.iloc[0])即可。
方法二:用向前填充(ffill)延续上一个有效水印值
如果你的场景中存在连续不满足条件的行,需要一直沿用最近一次满足条件的水印值,这种方式更合适:
tbid_cumsum = df['tbid'].cumsum() # 先只在满足条件的行赋值cumsum,其余行设为NaN df['Accum_tbid'] = np.where(df['cond'], tbid_cumsum, np.nan) # 向前填充NaN,同时处理首行可能的NaN(用0或其他初始值) df['Accum_tbid'] = df['Accum_tbid'].ffill().fillna(0)
这样连续不满足条件的行会自动继承上一次更新的水印值,首行的NaN也会被初始值覆盖。
方法三:自定义循环累加(适合小数据集)
如果你觉得向量化写法不够直观,也可以用循环逐行处理,逻辑完全贴合你的需求:
# 初始化累加值 current_accum = 0 accum_list = [] for _, row in df.iterrows(): if row['cond']: # 满足条件时更新累加值 current_accum += row['tbid'] # 不管满足与否,都添加当前累加值到列表 accum_list.append(current_accum) df['Accum_tbid'] = accum_list
这个方法逻辑清晰,但要注意:iterrows的效率较低,只适合小数据集;如果是百万级别的数据,优先用前两种向量化方法。
内容的提问来源于stack exchange,提问作者Giladbi
相关产品推荐
相关产品推荐

