Pandas稀疏DataFrame向前填充NaN的高效实现方法
加速稀疏DataFrame的递归填充:前一个非NaN值减1
你的需求本质是向前填充后,每个位置的值等于最近的前一个非NaN值减去它与该非NaN值之间的行数差,原来的循环方法因为多次调用fillna导致效率低下,我们可以用向量化操作来实现,速度和ffill相当。
核心思路
- 先用
ffill()获取每列的前向填充值,得到每个位置对应的最近非NaN基准值; - 计算每个位置到最近前一个非NaN值的行数偏移量(即从基准值开始往后数的第几个位置);
- 用基准值减去偏移量,得到最终填充结果。
实现代码
import pandas as pd import numpy as np # 初始化示例DataFrame df = pd.DataFrame(np.nan, index=range(10), columns=['A', 'B', 'C']) df.loc[(0,'A')] = 6 df.loc[(3,'A')] = 8 df.loc[(4,'B')] = 2 # 核心填充逻辑 mask = df.notna() ffilled = df.ffill() # 生成分组ID:每个非NaN值开始一个新分组 group_ids = mask.cumsum() # 计算每个组内的偏移量(从0开始计数) offsets = group_ids.apply(lambda col: col.groupby(col).cumcount()) # 计算最终结果 result_df = ffilled - offsets print(result_df)
运行后输出和你示例中的填充结果完全一致:
A B C 0 6.0 NaN NaN 1 5.0 NaN NaN 2 4.0 NaN NaN 3 8.0 NaN NaN 4 7.0 2.0 NaN 5 6.0 1.0 NaN 6 5.0 0.0 NaN 7 4.0 -1.0 NaN 8 3.0 -2.0 NaN 9 2.0 -3.0 NaN
性能优势
- 原来的循环方法需要遍历每一行,每次调用
fillna都会产生中间DataFrame,时间复杂度是O(n²)(n为行数); - 向量化方法只需要几次整体操作,时间复杂度是O(n),和
ffill的效率几乎一致,对于大尺寸DataFrame速度提升非常明显。
补充说明
- 对于全NaN的列(比如示例中的列C),结果会保持全NaN,符合预期;
- 如果DataFrame的行不是连续整数索引,这个方法依然有效,因为
cumcount是基于分组内的顺序计算偏移量的。
内容的提问来源于stack exchange,提问作者Giovanni De Gaetano
相关产品推荐
相关产品推荐

