处理数据的时候,缺胳膊少腿的字段永远是第一道关卡。我记得刚接手一份电商订单表的时候,一列“收货区域”里有将近40%是空值,旁边同事瞟了一眼就建议“直接删掉不就行了”。我先没急着删,跑了一行缺失统计,结果发现这40%的空值几乎集中在某个特定月份的订单里——如果当时手一抖全删掉,后面做月度区域销量分析时,那个月的数据会直接塌成一块空洞。缺失值删除这件事,看起来只是给dropna传几个参数的手艺活,但每一步取舍,其实都在悄悄影响后续结论的方向。
这篇文章要聊的就是“缺失值删除”这件事:什么时候能删、什么时候不能删、删行还是删列、以什么标准删,以及delete之外还有没有更好的选项。适合刚接触pandas、正在学数据清洗的学生和转行者,也适合日常处理报表、被空值反复折磨的运营和产品同学;如果你在做特征工程,需要决定训练样本里哪些行列能删、哪些必须保,这篇也能给你一套可参考的决策思路。不管用什么工具——Excel筛选、SQL写DELETE还是pandas里跑dropna——背后那套判断逻辑是通用的,别让“删除”成为头脑一热的肌肉记忆。
1. 删除缺失值之前,先给数据做一次“体检”
很多人拿到数据的第一个动作是看行数,第二个动作就是哪个字段有NaN就把它干掉。这个流程我当年也走过,直到有一次把一份关键字段缺失率只有2%的营销表删掉了6000多行,下游同事跑出来的人群覆盖率为0,我才反应过来:没有体检就动刀,跟闭着眼做手术没区别。
1.1 理解缺失模式:MCAR、MAR、MNAR
统计上把缺失分成三种模式,搞明白这些名词不是掉书袋,而是为了判断删完之后结果是否还有代表性。
-
完全随机缺失(MCAR):缺失跟数据本身没有任何关系,纯粹是采集时随机漏掉了。比如调查问卷里某几份答卷的某个选择题没填,这属于运气问题。这种情况下直接删掉缺失行,对剩余的总体分布几乎没影响,是最安全的一种删除场景。
-
随机缺失(MAR):缺失跟某些已观测到的变量有关系,但跟缺失值本身无关。举个例子,一份用户行为日志里,注册年份较早的老用户更容易缺失“首次来源渠道”这个字段,但“首次来源渠道”的具体值跟是否缺失没有关系。这种情况下,直接删缺失行,如果恰好删掉的都是老用户,后面分析新老用户特征时会引入偏差。
-
非随机缺失(MNAR):缺失与否跟缺失值本身有关,这是最棘手的情况。比如高端产品价格字段缺失,很可能是因为报价太高不敢填,或者低端设备上报失败导致某功耗字段缺失。这类缺失如果直接删行,留下的全是“敢填的”或者“设备好”的样本,系统性偏差几乎躲不掉。
对应到“能不能删”的结论上:MCAR可以放心删,MAR要看清关联字段再删,MNAR最好谨慎处理——先想想为什么缺,实在想不明白再考虑删除以外的方案。
1.2 用pandas和missingno快速定位缺失分布
做体检不是靠肉眼一行行看CSV,而是靠统计和可视化。我每次拿到新表格,固定会跑下面这段代码:
python复制import pandas as pd
df = pd.read_csv("order_data.csv")
# 1. 看每列的非空计数和类型,快速发现“看着有值其实是空字符串”的坑
df.info()
# 2. 每列缺失总数,按缺失率倒序
missing_df = pd.DataFrame({
"缺失数量": df.isnull().sum(),
"缺失率": df.isnull().mean()
}).sort_values("缺失率", ascending=False)
print(missing_df[missing_df["缺失率"] > 0].round(4))
df.info()会打印每列的非空数量,如果你的列名下面显示的Non-Null Count低于DataFrame的总行数,这一列就存在缺失。isnull().mean()算的就是每列的缺失比例,用sort_values排一下序,哪些字段是“重度缺失”一目了然。
可视化也很值得做,Python里我常用missingno这个库,几行代码就能看出缺失是随机散布,还是呈带状、成片出现:
python复制import missingno as msno
import matplotlib.pyplot as plt
# matrix图:每行是一条样本,每列是一个字段,白色条纹代表缺失
msno.matrix(df.sample(500))
plt.show()
# heatmap:看哪些字段倾向于一起缺失
msno.heatmap(df)
plt.show()
`matrix
