恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Pandas缺失值处理与数据填充的6种方法及业务选择

  • 首页
  • 资讯中心
  • /
  • Pandas缺失值处理与数据填充的6种方法及业务选择

相关资讯

CTF杂项信息隐藏实战:从PNG元数据到LSB隐写的完整链路 2026/10/9 17:24:09
不止是提示词:用 Skills 与 SKILL.md 让 ChatGPT 重复任务可靠又省力 2026/10/9 17:24:09
Claude.md的4个提效规则:用TaoToken统一Key打通AI辅助编程工作流 2026/10/9 17:24:09

最新资讯

Bootstrap网站模板选型实战指南:可维护性与工程化交付
∑是什么意思?从求和符号到算法复杂度与机器学习应用全解析
T3 Stack 全栈开发实战:用类型安全贯通前后端
程序员必修的数理逻辑实战指南:从命题逻辑到可计算性
jSignature移动端横屏签名板源码解析与真机避坑指南
MVX架构模式全解析:从MVC到MVI的演进逻辑与选型指南

今日推荐

AI编程智能体实战:从写代码到指挥代码的架构与落地
多模态大模型全栈能力拆解:从数据对齐到弹性推理
大模型Agent开发入门:从工具调用循环到落地避坑指南

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Pandas缺失值处理与数据填充的6种方法及业务选择

发布时间:2026/10/9 17:24:09
Pandas缺失值处理与数据填充的6种方法及业务选择 做数据分析的人十有八九都会在“缺失值”这儿卡过壳。数据清洗这个词听着简单真正上手做的时候全是细节。尤其是数据填充这一环——面对一列NaN是填0、填均值、往前补、插个值还是干脆扔给模型去猜每个选择背后都悄悄影响着后续的统计口径和模型效果。这篇文章我就把pandas里最常用的6种数据填充方式掰开揉碎讲一遍结合具体业务场景给出选择建议和避坑经验适合正在为缺失数据头疼的数据分析师、算法工程师也适合刚入门想系统搞懂数据清洗的同学。内容不会停留在API表面而是尽量把“为什么这么选”讲清楚让大家看完能直接用到自己的数据上。1. 先别急着填充摸清缺失值的底细再动手很多新手拿到数据看到NaN就条件反射执行df.fillna(0)这是最常见的坑。填充不是单纯把空位补上而是一个带有业务判断的动作。在动手之前我建议先花10分钟搞清楚两个问题这份数据的缺失是什么性质、缺到什么程度。缺失值大致分三种类型。第一种是完全随机缺失MCAR比如客户填问卷时手滑漏了一题这种缺失跟任何字段都无关处理起来最安全第二种是随机缺失MAR缺失跟其他变量有关比如高收入人群更不爱填“月收入”这一栏这时如果你直接填均值就会把整体收入水平拉低第三种是非随机缺失MNAR缺不缺失跟它自身的真实值有关比如极高的收入者刻意不填收入。第三种最难处理单靠填充技术解决不了需要更谨慎的建模手段。动手之前先用一行代码给数据做个“体检”import pandas as pd # 统计每个字段的缺失数量与缺失率 missing_count df.isna().sum() missing_rate df.isna().mean().round(4) missing_summary pd.DataFrame({ 缺失数量: missing_count, 缺失率: missing_rate }).sort_values(缺失率, ascendingFalse) print(missing_summary)然后根据缺失率分档处理缺失率低于5%的字段如果样本量充足直接删除这几行往往影响不大缺失率在5%到20%之间适合用填充策略超过40%的字段除非业务上非常重要否则建议直接弃用。这个阈值不是绝对的但能帮你快速聚焦精力。还要判断一下NaN本身有没有业务含义。比如“客户是否申请过贷款”这一列没申请的人记录为NaN那就是“0”的意思这时填充为“否”才是对的硬填均值反而闹笑话。2. 六种填充方式逐个拆解从“无脑填”到“精细补”2.1 常数填充最直接但别啥都填0常数填充就是给所有缺失值填同一个固定值语法最简单。df.fillna(0)、df.fillna(未知)、df.fillna(-1)都是这个套路。它的核心逻辑是“用一个占位值告诉后续分析这里本来就没有有效数据”。但“填0”有一个很隐蔽的副作用数值列填0会大幅拉低均值、中位数扭曲分布。比如“月消费金额”这一列缺失原因可能是客户当月没有任何消费记录这时候填0完全合理但如果缺失原因是系统漏录单填0就会把人均消费额往下拽做报表时直接被老板质疑数据有问题。更讲究一点的做法是按列指定填充值。pandas的fillna()支持传字典可以给不同列填不同内容df.fillna({ age: 0, # 年龄缺失的先用0占位 income: df[income].median(), # 收入缺失的填中位数 region: 未知地区 }, inplaceTrue)我个人的经验是常数填充适合那些“缺失即无意义”的场景比如营销活动的参与次数、优惠券的使用次数不适合那些缺失后依然需要参与统计计算的核心指标列。2.2 统计量填充均值、中位数、众数怎么选统计量填充是应用最广的一类核心思路是用已有数据的统计特征去代替缺失值。常见的统计量有三个均值、中位数、众数。均值填充的前提是数据接近正态分布、没有极端异常值。比如电商订单的“购买数量”一般比较稳定填均值不会引起大的偏倚。但“个人收入”“房屋面积”这类长尾分布字段直接填均值会被极少数高值拉高填完之后数据的方差会被严重低估模型预估也会偏向中心。中位数填充则稳健得多。只要字段里有明显的离群值我一般优先选中位数。比如一组收入数据大部分在5000到15000之间有几个人月入百万此时均值可能被拉到两三万而中位数还停留在8000附近显然中位数更能代表“普通人的水平”。众数填充用于分类变量比如“城市”列缺失用出现次数最多的城市来补简单且解释成本低。还有一种更细致的操作叫分组填充。先按某个关键字段分组再在各组内填统计量效果比全局填充好得多。举个例子被调查者的“收入”缺失了但每个人有“所在城市”一线城市和三线城市的收入水平差距很大全局填一个均值显然不合理按城市分组后用各城市自己的收入中位数去填充数据就自然多了。df[income] df.groupby(city)[income].transform( lambda x: x.fillna(x.median()) )使用sklearn的话SimpleImputer也可以做到类似的事而且能直接塞进pipeline里from sklearn.impute import SimpleImputer imputer SimpleImputer(strategymedian) # 也可以填mean或most_frequent df[[income]] imputer.fit_transform(df[[income]])统计量填充最大的弱点在于它是“用平均代替个体”会系统性降低数据的变异性。这也是我后来在建模时特别留意的地方——如果特征的方差本身就是模型的信号来源填充后模型性能会下降这时就该考虑插值或模型填充了。2.3 前向填充与后向填充顺序敏感场景的默认答案如果说统计量填充是“横着看”前向填充和后向填充就是“竖着看”沿着索引的顺序把上一个有效值搬运到缺失位置上。# 前向填充用前面的值补后面的空缺 df[value].fillna(methodffill) # 等价写法 df[value].ffill() # 后向填充用后面的值补前面的空缺 df[value].fillna(methodbfill) # 等价写法 df[value].bfill() # 限制连续填充数量防止搬运过度 df[value].ffill(limit2)很多同学不理解顺序为什么这么重要。可以类比一下给空白硬盘写入数据磁盘写入时必须按照磁道、扇区的物理顺序逐一定位寻址跳着写会导致后续读取混乱。pandas的填充也一样先有索引顺序才能谈向前还是向后。也就是说使用这类方法前必须确保索引是有意义的——时间序列按时间排序表格数据按业务逻辑排好序。这个方法最适合两类场景一是传感器或日志数据设备某一秒没上报用前一秒的数值顶上很自然二是从Excel读取的合并单元格数据只有每个合并区块左上角才有值下面全是NaNffill()一拉表格就顺了。前向填充不会产生任何“新值”它只是复制所以数据分布几乎不变。但方向搞反会出大事。如果数据本身按时间倒序排列你以为是向前补实际上补到的是未来值。我的习惯是填充前先df.sort_index()或明确按时间字段排序确认方向是对的。2.4 插值填充让缺失值顺着趋势“长出来”插值填充的思路更聪明一点它不直接搬一个现成的值而是根据缺失点两侧的已有数据拟合出一个趋势线再算出缺失点的估计值。pandas的interpolate()方法默认使用线性插值# 线性插值把缺失前后两点连成直线取对应位置的值 df[value].interpolate() # 时间感知插值按实际时间间隔来插值适合不规则时间序列 df[value].interpolate(methodtime) # 多项式插值用多项式拟合趋势order控制阶数 df[value].interpolate(methodpolynomial, order2) # 样条插值更平滑适合波动平缓的曲线 df[value].interpolate(methodspline, order3)线性插值有一个隐含假设缺失段内数据近似线性变化。这个假设在连续型指标上经常成立比如温度、库存量、用户活跃度这类随时间平滑变化的数据插出来的值比填均值自然得多。但插值不是万能的。分类变量千万不能用插值——“地区”这一列插出一个“华东南部”就闹大笑话了。另外polynomial和spline插值容易出现“过冲”现象也就是在数据拐弯的地方插出比实际范围更大的值比如销售额不可能为负数但多项式插值可能给你插出一个负数来。后处理时可以用clip(lower0)把越界值拉回合理区间。2.5 预测模型填充让其他列的信息帮你“猜”出缺失值前面几种方法都只用到了单列自身的信息。预测模型填充则更进一步把缺失列当作目标变量用其他列作为特征训练一个模型去预测缺失值。这是信息利用最充分、但代价也最高的一种方式。最简单的实现是跑一个线性回归。比如“收入”缺失但是我们有“年龄”“城市”“职业”“学历”这些和收入高度相关的字段就可以先用有收入的样本训练模型再用训练好的模型预测缺失样本的收入。sklearn里的IterativeImputer和KNNImputer把这件事封装好了from sklearn.experimental import enable_iterative_imputer from sklearn.impute import IterativeImputer, KNNImputer # 多重链式方程填充 imp IterativeImputer(max_iter10, random_state42) df_filled imp.fit_transform(df) # KNN填充找特征最相似的K个样本用它们的均值补缺失值 knn_imp KNNImputer(n_neighbors5) df_filled knn_imp.fit_transform(df)KNN的原理可以简单理解成“人以群分”先找到和缺失样本在特征上最相似的5个邻居用邻居在这个字段上的平均值去填充。有几个细节要注意做KNN填充前其他特征列都必须是数值型且没有缺失值所以通常要先用常数或统计量把其他列粗填充一遍特征量纲不一致时还要先做标准化否则距离计算会被量纲大的列带偏。我个人建议只有在样本量足够大、特征与缺失列相关性较强的时候才上模型填充。否则模型是从噪音中学习规律填出来的值看着合理实际上一跑交叉验证就露馅。试过一次就会发现模型填充的成本不只是算力还有验证成本得格外小心过拟合。2.6 标记法让缺失本身变成一种信号最后一种方式思路完全不同我不“补”缺失值而是把“是否缺失”这件事单独变成一个特征。因为不少场景下缺失本身就是业务信号。比如客户填资料时学历缺失这部分客户往往更不配合、潜在风险更高那缺失这个状态比学历填什么都更有区分度。实现方式很简单给每个含缺失的字段加一列布尔标记再配合常数填充使用。df[income_missing] df[income].isna().astype(int) df[income] df[income].fillna(-1) # 填充一个中立值在机器学习项目里我经常用特征工程的方式保留缺失信息比如用sklearn.impute.MissingIndicatorfrom sklearn.impute import MissingIndicator indicator MissingIndicator(featuresmissing-only) missing_flags indicator.fit_transform(df) missing_df pd.DataFrame(missing_flags, columnsindicator.features_)标记法跟前面几种填充并不冲突而是互补的。实操中我常用的组合是填均值保持数值可用同时挂一个isnull标记列让模型自己决定“缺失”这个状态有没有用。特别是XGBoost、LightGBM这类树模型本身能处理缺失值但如果你先用业务规则做了填充再额外给一个标记列往往能看到模型效果的小幅提升。3. 实操过程一个电商用户表从乱到干净3.1 准备数据集和缺失全景图拿一个常见的电商场景练手。假设有一份用户订单表包含user_id、age、income、region、spend、register_days六个字段其中income缺失率约30%region缺失率约8%age和spend有零星缺失。构造一份模拟数据import pandas as pd import numpy as np rng np.random.default_rng(42) n 2000 df pd.DataFrame({ user_id: range(1, n 1), age: rng.integers(18, 60, n).astype(float), income: rng.normal(8000, 2500, n).astype(float), region: rng.choice([华东, 华南, 华北, 西南], n), spend: rng.normal(300, 80, n).astype(float), register_days: rng.integers(1, 365, n).astype(float), }) # 人为制造缺失 df.loc[rng.choice(n, 600, replaceFalse), income] np.nan df.loc[rng.choice(n, 160, replaceFalse), region] np.nan df.loc[rng.choice(n, 100, replaceFalse), age] np.nan df.loc[rng.choice(n, 80, replaceFalse), spend] np.nan先跑一遍缺失率统计得到income缺失30%、region缺失8%、age缺失5%、spend缺失4%。基于这个结构再逐列判断用哪种填充策略。3.2 按业务逻辑逐个字段做填充region是分类变量缺失属于登记遗漏用众数填充没问题而且解释成本低。age是连续变量但有极端值风险比如刷单小号年龄填的99岁用中位数比均值稳。income长尾分布明显全局填中位数依然不够细我选择按region分组之后填中位数这样每个地区维持自己的收入水平。spend是连续且趋势较强的指标直接用线性插值顺着时间按register_days排序后补会比较自然。# 分类变量众数填充 df[region] df[region].fillna(df[region].mode()[0]) # 连续变量分组中位数填充 df[income] df.groupby(region)[income].transform( lambda x: x.fillna(x.median()) ) # 年龄全局中位数填充并做范围约束 age_median df[age].median() df[age] df[age].fillna(age_median).astype(int) # 消费金额先按注册天数排序再线性插值 df df.sort_values(register_days).reset_index(dropTrue) df[spend] df[spend].interpolate(methodlinear)填充时我顺手做了一件事把填充后的age转成整数避免出现“年龄25.5岁”这种反直觉结果。这也是一个很容易遗漏的细节。3.3 填充效果对比不是每列都适合同一种方法光填完还不够得验证是否过度变形。我保留了模拟时的原始真值所以能直接对比不同填充方式对分布的影响。下面这个表是同一份income字段用不同方法填充后的统计指标对比填充方式均值标准差中位数潜在问题原始数据无缺失798225107950基准全局均值填充798021307950标准差被压缩峰变高全局中位数填充796522757950方差仍被压缩分组中位数填充797824367960分布保持较好KNN填充797523887945效果接近分组填充但耗时更高填补0553033507950均值严重失真不可用从这个表能直观看出两个结论第一填0在业务上解释不通时对统计指标伤害极大第二分组填充在分布还原度上明显优于全局填充差异虽小但放到下游回归模型里一点偏差都会被放大。验证分布还有一种更直观的方法把填充前后的数据画在同一张密度图上。如果填充后的曲线在均值附近出现异常尖峰说明填充方法过于粗暴。观察kde曲线的形态几乎一眼就能判断出填充结果是否自然。4. 常见问题与排查技巧实录4.1 时间序列里ffill和bfill方向搞混补救要趁早前向填充和后向填充的方向高度依赖数据排序。我在一个真实项目里接过一份按日期倒序排列的销量数据同事用ffill()填充后每个缺失值都补上了“未来”的销量整个趋势分析全部失真。排查时先别急着怀疑算法停一下df.head()看看索引顺序再确认一次业务含义。时间序列的填充永远先排序、后填充、再检查尾部数据是否为NaN。4.2 合并单元格导入后出现“半个表格的NaN”这是Excel数据进pandas时非常经典的坑Excel里的合并单元格只有左上角单元格存了值合并区域的其他格子在pandas眼里全是NaN。如果直接填充0或均值等于把合并区块里的语义结构全毁了。正确的做法是先用ffill()把合并值向下传播df[部门] df[部门].ffill()这样每个员工行都能拿到自己的部门归属。处理完后还要抽查一下确认没有把不同区块的值串行尤其是合并单元格跨行不规整时ffill()可能会把上一个区块的尾巴接到下一个区块头上。4.3 interpolate用错算法导致出现离谱负值插值方法看着友好但算法选错很尴尬。一次做温度数据插值用polynomial三阶插值后突然出现一个-12度的数值——当天气温在5到20度之间这不是测量异常纯粹是多项式在边界区域过冲了。解决办法有两条第一优先使用线性或时间插值第二插值后加一道clip限制范围。我后来养成了习惯任何插值后的数值都先看一眼min()和max()越界值再单独处理。另外interpolate()的索引默认顺序是行号如果行号本身没含义线性插值的结果也会很莫名。4.4 填充后数据分布完全变形却没人发现统计量填充最大的隐患就是方差被压缩但这个变化很隐蔽。普通报表可能只看均值看不出问题到了建模阶段特征方差变小系数估计就会偏。排查方法很简单填充前后各跑一次df.describe()重点看标准差那一行或者用seaborn.kdeplot对比前后分布曲线。发现方差异常缩小就说明填充方式过于“平滑”该上插值、模型填充或分组填充了。5. 我个人踩过这些坑之后沉淀下来的几条填充经验跟数据打了这些年交道填充这件事我慢慢形成了自己的优先级能直接删就删缺失率极低时删不了就先按业务规则填业务规则定不下来再退到分组统计量最后才上插值和模型。这个顺序不是按精度排的而是按“可解释性”排的。越是复杂的填充方法越要警惕它是否引入了你以为它没有的假设。还有一个小习惯很管用每次做填充都在项目文档里记一行说明哪个字段用了什么方法、为什么这样选、填充参数是什么。不要小看这行记录一个月后你回看自己的代码会感谢当初那个写备注的自己。另外填充值最好在分析阶段单独存储不要直接覆盖原始列。我会新建一个filled_前缀的列保留原始NaN列做参考这样方便随时回溯、重新评估。最后分享一个从实战里摸出来的巧劲如果要做模型预测试试给填充后的数据集跑一版“不填充 缺失标记”的对照组。很多时候你会发现树模型对缺失值的处理比你的填充策略更聪明让模型自己决定缺失值怎么分叉效果反而更好。数据清洗没有放之四海而皆准的答案多对比、多验证才能找到最适合当前业务场景的那一种。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号