正确做法是仅对数值列调用fillna(df.mean())或interpolate(),时间序列需指定method='time',混合类型列须分类型处理,且插值后需用ffill/bfill补充首尾NaN。

用 fillna() 填均值时,别直接传 df.mean()
直接写 df.fillna(df.mean()) 看似简洁,但会把所有列缺失值都用整行的均值填充——这是错的。Pandas 默认按列对齐,df.mean() 返回的是每列均值组成的 Series,而 fillna() 能正确广播它;但如果你先用 df.mean().mean() 得到一个标量再填,就全填成同一个数了。
正确做法是:
- 数值列单独处理:
df[numeric_cols] = df[numeric_cols].fillna(df[numeric_cols].mean()) - 想跳过非数值列?加
numeric_only=True:df.fillna(df.mean(numeric_only=True)) - 注意:
mean()默认跳过NaN,但若整列全是NaN,结果为NaN,再填进去还是NaN——得提前检查
interpolate() 默认线性插值,但时间序列得标定 method='time'
对带时间索引的 DataFrame,比如每 5 分钟一条记录,直接用 df.interpolate() 会按行号等距插值,而不是按真实时间间隔。结果就是:两行之间隔了 2 小时,它却当成 1 步来算。
必须显式指定时间感知方式:
立即学习“Python免费学习笔记(深入)”;
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 索引已是
DatetimeIndex?用df.interpolate(method='time') - 索引是普通整数,但有一列叫
'timestamp'?先设为索引:df.set_index('timestamp').interpolate(method='time').reset_index() -
method还支持'values'(默认,按索引值)、'index'(同'values')、'polynomial'(需指定order)等,但非时间场景慎用高阶多项式,容易震荡
混合类型列遇到 fillna() 或 interpolate() 会报错
Pandas 对字符串、布尔、分类等类型列不支持插值,interpolate() 直接抛 TypeError: Cannot interpolate with object dtype;fillna() 虽能填,但若你传入的是数值均值,会强制转类型,比如字符串列填进数字 3.2,整列变 object 且内容变成 '3.2' 字符串。
稳妥做法是分类型处理:
- 先分离列类型:
num_cols = df.select_dtypes(include='number').columns.tolist() - 只对数值列插值:
df[num_cols] = df[num_cols].interpolate() - 类别列用众数:
df[cat_cols] = df[cat_cols].fillna(df[cat_cols].mode().iloc[0])(注意mode()可能返回多行,取第一行) - 千万别对整 DataFrame 直接调
interpolate(),除非你确认没非数值列
插值后记得检查边界——首尾 NaN 不会被填充
interpolate() 默认只填充中间的缺失段,开头连续 NaN 和结尾连续 NaN 都保留。比如数据从第 3 行开始有值,前两行是 NaN,插完还是 NaN。
需要向前/向后延展?得组合使用:
- 先插中间:
df.interpolate() - 再补头尾:
df.fillna(method='ffill').fillna(method='bfill') - 或者一步到位:
df.interpolate(limit_area='inside').fillna(method='ffill').fillna(method='bfill'),其中limit_area='inside'明确限定只插内部,避免和前后向填充逻辑冲突 - 注意顺序:先
interpolate再ffill/bfill,反过来的话,前向填充可能把本该插值的位置提前填死,导致插值失效
实际跑之前,用 df.isna().sum() 对比前后,尤其盯住首尾几行——那里最容易漏掉。

















