4. 缺失值处理(上):缺失值识别、统计与可视化
各位好,今天我们聊聊数据清洗里最让人头疼,但也最基础的问题——缺失值。
说实话,我做了这么多年数据治理,见过太多因为缺失值处理不当,导致整个模型崩掉的案例。你想想看,数据里缺一块,就像盖房子少了几块砖,后面再怎么折腾也白搭。
所以,咱们第一步不是急着去填坑,而是先搞清楚:到底哪些地方缺了?缺了多少?缺得有没有规律?
4.1 缺失值识别:先找到“洞”在哪
在Python里,识别缺失值其实就两行代码的事。但我个人习惯,拿到数据后第一件事不是跑代码,而是先看一眼数据长什么样。
import pandas as pd
import numpy as np
# 加载数据
df = pd.read_csv('sales_data.csv')
# 快速看一眼
print(df.head())
print(df.info())
print(df.shape)
df.info() 会告诉你每列有多少个非空值。如果某列的非空数量明显少于总行数,那就有问题了。
更精确的识别,用 isnull():
# 返回布尔值,True表示缺失
print(df.isnull().head())
# 或者反过来看哪些是正常的
print(df.notnull().head())
我在项目中遇到过一种情况:某列看起来全是数字,但实际有些单元格是空字符串 '' 或者 'N/A'。这些 pandas 默认不认为是缺失值,需要手动处理。
df.replace(['', 'N/A', 'NULL', 'None'], np.nan, inplace=True) 先把这些“假值”转成真正的缺失值。
4.2 缺失值统计:量化缺失的严重程度
识别出缺失值后,下一步就是量化。说白了,就是算算每列缺了多少,占比多少。
# 每列缺失总数
missing_count = df.isnull().sum()
print(missing_count)
# 每列缺失比例
missing_ratio = df.isnull().sum() / len(df) * 100
print(missing_ratio)
# 合并成一个表格
missing_df = pd.DataFrame({
'缺失数量': missing_count,
'缺失比例(%)': missing_ratio.round(2)
})
print(missing_df)
我个人习惯把缺失比例超过30%的列标红。为什么是30%?嗯,这个阈值其实没有绝对标准,但我在多个项目里试下来,超过这个比例,填充的意义就不大了,不如直接考虑删除或者做特征工程。
| 列名 | 缺失数量 | 缺失比例(%) | 处理建议 |
|---|---|---|---|
| customer_age | 12 | 2.4% | 可填充 |
| income | 158 | 31.6% | 考虑删除或建模 |
| phone_number | 423 | 84.6% | 建议删除 |
df.isnull().sum().sort_values(ascending=False) 把缺失最多的列排在最前面,一眼就能看出哪些列是“重灾区”。
4.3 缺失值可视化:用 missingno 库一眼看穿
光看数字还不够,有时候数据缺失是有规律的。比如,某个时间段的数据集体缺失,或者某几列总是同时缺失。这时候,用 missingno 库就特别方便。
先安装:
pip install missingno
然后导入并使用:
import missingno as msno
import matplotlib.pyplot as plt
# 1. 矩阵图:白色表示缺失,黑色表示存在
msno.matrix(df)
plt.show()
# 2. 条形图:每列缺失比例一目了然
msno.bar(df)
plt.show()
# 3. 热力图:看列与列之间缺失的相关性
msno.heatmap(df)
plt.show()
# 4. 树状图:看缺失值的聚类模式
msno.dendrogram(df)
plt.show()
我重点说说矩阵图。你想想看,如果数据是按时间排序的,矩阵图上出现一整片白色横条,那就说明那段时间的数据集体缺失了。这种情况我遇到过好几次,最后发现是采集系统在那段时间宕机了。
热力图也很有用。它显示的是两列之间缺失的相关性。比如,income 和 education 的缺失相关性是0.8,那就说明这两列很可能同时缺失。为什么会这样?可能是因为填写问卷的人跳过了这两个问题。
下面这张图,是我用 SVG 画的一个知识结构图,帮你理清今天讲的内容:
好了,今天的内容就到这里。记住,缺失值处理不是一上来就填,而是先看清楚、算明白、画出来。下一节我们接着聊怎么处理这些缺失值——是填?是删?还是留着?到时候再细说。