Pandas技巧:计算各时间戳下每列非NaN记录的累积计数
问题:计算Pandas DataFrame每列非NaN值的累积计数
你完全可以用Pandas内置的向量化操作实现,不需要低效的循环,既简洁又高效。先还原你的原始数据:
import pandas as pd import numpy as np df = pd.DataFrame({ 'timestamp': ['2016-02-15 00:00:00', '2016-02-15 00:01:00', '2016-02-15 00:02:00', '2016-02-15 00:03:00', '2016-02-15 00:04:00', '2016-02-15 00:05:00', '2016-02-15 00:06:00', '2016-02-15 00:07:00', '2016-02-15 00:08:00'], 'col_A': [2.0, 1.0, 4.0, 2.0, 7.0, 2.0, 2.4, 2.0, 2.5], 'col_B': [np.nan, np.nan, 2.0, 2.0, 4.1, 5.0, 2.0, 6.3, 7.0], 'col_C': [np.nan, np.nan, np.nan, np.nan, 1.0, 2.0, 7.5, 1.2, np.nan] })
你的需求是计算每个时间戳下,每列非NaN记录的累积计数,预期输出如下:
# 预期输出 timestamp col_A col_B col_C 0 2016-02-15 00:00:00 1 NaN NaN 1 2016-02-15 00:01:00 2 NaN NaN 2 2016-02-15 00:02:00 3 1 NaN 3 2016-02-15 00:03:00 4 2 NaN 4 2016-02-15 00:04:00 5 3 1 5 2016-02-15 00:05:00 6 4 2 6 2016-02-15 00:06:00 7 5 3 7 2016-02-15 00:07:00 8 6 4 8 2016-02-15 00:08:00 9 7 NaN
优雅的实现方式
核心思路是先标记非NaN值为1、NaN为0,再对每列做累积求和,最后还原原始NaN位置的值:
# 1. 标记非NaN值为1,NaN为0 non_nan_mask = df[['col_A', 'col_B', 'col_C']].notna().astype(int) # 2. 计算每列的累积计数 cumulative_counts = non_nan_mask.cumsum() # 3. 将原始NaN位置的计数重新设为NaN result_counts = cumulative_counts.where(df[['col_A', 'col_B', 'col_C']].notna()) # 4. 合并timestamp列得到最终结果 result = pd.concat([df['timestamp'], result_counts], axis=1) print(result)
如果追求极致简洁,也可以把步骤合并成一行:
result = pd.concat([ df['timestamp'], df[['col_A', 'col_B', 'col_C']].notna().astype(int).cumsum().where(df[['col_A', 'col_B', 'col_C']].notna()) ], axis=1)
为什么这比循环更好?
- 性能更高:Pandas的
notna()、cumsum()都是底层优化的向量化操作,数据量大时比Python循环快几个数量级 - 代码更易读:用内置方法表达逻辑,不需要手动处理索引和逐行判断,减少出错概率
- 维护更简单:后续修改需求只需调整链式调用的步骤,无需重构循环逻辑
内容的提问来源于stack exchange,提问作者Edamame
相关产品推荐
相关产品推荐

