ffill()和bfill()适用于连续空值,速度快但仅处理NaN/None;interpolate()适合有物理意义的空缺,需DatetimeIndex支持time插值;fillna()结合rolling可做局部统计填充;注意inplace=True在Series中无效,须分步赋值或用df.fillna()字典参数。

用 ffill() 和 bfill() 填充连续空值最直接
多数情况下,序列里出现的空值是连续的“缺口”,比如传感器断连、日志漏写。这时 ffill()(前向填充)和 bfill()(后向填充)是最轻量、最快速的选择,底层用 C 实现,比循环快一个数量级。
注意:它们默认只对 NaN 或 None 生效,不处理字符串 "null" 或数值 -999 这类伪空值——得先用 replace() 或布尔索引清洗。
-
df["col"].ffill(limit=2)只向前填充最多 2 个位置,防止单个长缺口污染后续数据 -
df["col"].bfill().ffill()先补尾再补头,适合首尾都有缺失的时序场景 - 对
Series直接调用即可;对DataFrame需指定axis,如df.ffill(axis=0)
用 interpolate() 做线性/时间加权插值
当空缺位置有明确物理意义(比如温度随时间变化),简单前后填会扭曲趋势。interpolate() 更合理,尤其搭配 method="time" 或 method="linear"。
关键点:必须确保索引是 DatetimeIndex 才能用 method="time";否则它退化为按整数位置插值,结果可能反直觉。
立即学习“Python免费学习笔记(深入)”;
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
-
s.interpolate(method="time", limit_area="inside")只插中间缺口,跳过开头结尾的NaN -
s.interpolate(limit=3)控制单次插值最大跨度,避免跨过大段异常空白 - 性能上比
ffill略慢,但对百万元素以下数据几乎无感
用 fillna() + 自定义函数应对非均匀缺口
如果空值分布稀疏且不规则(比如某列每 10 行随机缺 1 个),而你又需要基于邻近非空值的统计量填充(如局部均值、中位数),fillna() 结合 rolling().mean() 是稳妥解法。
别直接用 mean() 全局填充——会掩盖局部漂移;也别在滚动窗口里包含 NaN 计算,会导致结果全 NaN。
-
s.fillna(s.rolling(5, center=True).median().fillna(s.median())):先滚动中位数,空处 fallback 到全局中位数 -
rolling()的min_periods=1能让边缘窗口不返回NaN,但需确认是否符合业务逻辑 - 滚动计算本身不修改原序列,
fillna()才真正覆盖,顺序不能颠倒
警惕 inplace=True 在链式调用中的失效
很多人写 df["col"].ffill(inplace=True) 发现没生效——因为 Series.ffill() 返回新对象,inplace=True 只对 DataFrame 方法(如 df.fillna(..., inplace=True))可靠生效。
更隐蔽的问题:链式操作如 df["col"].ffill().interpolate() 中,第一个方法返回副本,第二个操作在此副本上进行,原始 df 完全没变。
- 安全写法是分步赋值:
df["col"] = df["col"].ffill().interpolate() - 或统一用
df.fillna()配合字典传参:df.fillna({"col1": "ffill", "col2": "bfill"}) - 对大型 DataFrame,重复赋值有内存开销,可考虑
df.loc[:, "col"] = ...原地修改视图
ffill/bfill;带时间语义选 interpolate(method="time");局部波动大就上滚动统计。填完务必用 df.isna().sum() 核对,别依赖肉眼判断。

















