4、缺失值处理(上):缺失值检测(isnull/notnull)、缺失值统计与可视化
数据清洗里,缺失值处理是绕不开的一关。
我做了这么多年投研平台,见过太多因为缺失值没处理好,导致模型跑偏、回测结果虚高的案例。说白了,缺失值就是数据里的「黑洞」——你不把它找出来,它就会在背后悄悄搞事情。
这一节,我们先解决最基础的问题:怎么发现缺失值?怎么统计它?怎么把它画出来?
4.1 缺失值长什么样?
在 pandas 里,缺失值通常用 NaN(Not a Number)表示。但实际数据里,它可能伪装成 None、空字符串 '',甚至是 0 或 -999。
嗯,这里要注意:0 不是缺失值,它是真实值。我遇到过有人把 0 当缺失值删了,结果收益率曲线直接崩了。
4.2 缺失值检测:isnull() 和 notnull()
这两个函数是检测缺失值的基本工具。
isnull():返回布尔值,缺失为True,否则False。notnull():正好相反,缺失为False,否则True。
我个人习惯先用 isnull() 扫一遍,心里有个底。
import pandas as pd
import numpy as np
# 模拟一份投研数据
df = pd.DataFrame({
'股票代码': ['000001', '000002', '000003', '000004'],
'收盘价': [10.5, np.nan, 11.2, np.nan],
'成交量': [100000, 200000, np.nan, 150000],
'市盈率': [8.5, 9.2, np.nan, np.nan]
})
# 检测缺失值
print(df.isnull())
输出结果长这样:
股票代码 收盘价 成交量 市盈率
0 False False False False
1 False True False False
2 False False True True
3 False True False True
你看,True 的位置就是缺失值。一眼就能看出哪些地方有问题。
df.isnull().sum() 直接看每列有多少缺失值,比肉眼扫快得多。
4.3 缺失值统计:到底缺了多少?
光知道哪里缺还不够,你得知道缺了多少、占比多少。这决定了你后续怎么处理——是删、是补、还是留着。
我一般会做三件事:
- 按列统计缺失数量
- 按列统计缺失比例
- 按行统计缺失数量
# 按列统计缺失数量
missing_count = df.isnull().sum()
print("每列缺失数量:")
print(missing_count)
# 按列统计缺失比例
missing_ratio = df.isnull().mean() * 100
print("\n每列缺失比例(%):")
print(missing_ratio)
# 按行统计缺失数量
row_missing = df.isnull().sum(axis=1)
print("\n每行缺失数量:")
print(row_missing)
输出结果:
每列缺失数量:
股票代码 0
收盘价 2
成交量 1
市盈率 2
dtype: int64
每列缺失比例(%):
股票代码 0.0
收盘价 50.0
成交量 25.0
市盈率 50.0
dtype: float64
每行缺失数量:
0 0
1 1
2 2
3 2
dtype: int64
你看,收盘价 和 市盈率 都缺了一半。这种比例,直接删掉就太可惜了。我曾经在回测时删掉了一列缺失率 40% 的因子,结果模型 AUC 掉了 0.15——后来发现那个因子虽然缺得多,但信息量很大。
4.4 缺失值可视化:一张图胜过千言万语
数字统计很精确,但不够直观。我习惯用可视化来快速定位缺失模式。
常用的工具有两个:missingno 和 seaborn.heatmap。
4.4.1 使用 missingno 库
missingno 是专门做缺失值可视化的库,轻量又好用。
import missingno as msno
import matplotlib.pyplot as plt
# 缺失值矩阵图
msno.matrix(df)
plt.show()
# 缺失值条形图
msno.bar(df)
plt.show()
# 缺失值相关性热力图
msno.heatmap(df)
plt.show()
- matrix 图:白色条带就是缺失位置,一眼看出缺失是否集中。
- bar 图:每列缺失数量的柱状图,适合快速对比。
- heatmap 图:显示列与列之间缺失的相关性。如果两列经常同时缺失,说明可能有共同原因。
4.4.2 使用 seaborn 热力图
如果你不想装额外库,用 seaborn 也能画缺失热力图。
import seaborn as sns
# 先转成布尔矩阵,再画热力图
sns.heatmap(df.isnull(), cbar=False, cmap='viridis')
plt.title('缺失值热力图')
plt.show()
深色代表缺失,浅色代表有值。这种图适合看整体分布,但不如 missingno 精细。
4.5 知识体系总览
下面这张图,把缺失值检测的核心逻辑串起来了。我建议你保存下来,以后做清洗时对照着看。
4.6 避坑指南
最后,分享几个我踩过的坑:
- 别只看 NaN:有些数据用
-999、9999或空字符串表示缺失。记得先做值域检查。 - 时间序列的缺失要小心:股票数据里,非交易日就是缺失。这种缺失是正常的,别乱补。
- 缺失模式比缺失数量更重要:如果缺失是随机的,填充均值问题不大。如果是系统性的(比如某只股票连续10天缺失),那就要深挖原因了。
公众号:蓝海资料掘金营,微信deep3321