4. Pandas 缺失值基础:isnull()、notnull()、info()、describe() 等基础检测方法
在特征工程中,处理缺失值的第一步不是“怎么填”,而是“哪里缺、缺多少、缺什么类型”。Pandas 提供了四组核心方法,帮助数据科学家快速建立对缺失数据的全局认知。本章将逐一拆解这些方法的输出含义与实战用法。
4.1 缺失值检测的“显微镜”:isnull() 与 notnull()
isnull() 返回与原始 DataFrame 形状相同的布尔矩阵,缺失位置为 True,非缺失为 False。notnull() 则完全相反。这两个方法是所有后续缺失值统计与筛选的基石。
核心用法:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [np.nan, 2, 3, 4],
'C': ['x', 'y', None, 'z']
})
# 布尔矩阵
print(df.isnull())
# 统计每列缺失数量
print(df.isnull().sum())
# 筛选至少有一个缺失值的行
print(df[df.isnull().any(axis=1)])
# 筛选全部非缺失的行
print(df[df.notnull().all(axis=1)])
| 方法 | 返回类型 | True 的含义 | 常用组合 |
|---|---|---|---|
isnull() |
DataFrame (bool) | 该位置是缺失值 | .sum()、.any()、.mean() |
notnull() |
DataFrame (bool) | 该位置是非缺失值 | .all()、.sum() |
实战技巧:使用
df.isnull().mean() 可以直接得到每列的缺失率(0~1 之间),比手动计数除以行数更简洁。
4.2 数据集的“体检报告”:info()
info() 是 Pandas 中最常用的数据概览方法,它一次性输出行数、列数、每列的非空计数、数据类型和内存占用。对于缺失值检测,重点关注 非空计数(Non-Null Count) 与总行数的差值。
典型输出解读:
df.info()
# 输出示例:
#
# RangeIndex: 1000 entries, 0 to 999
# Data columns (total 8 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 age 1000 non-null float64
# 1 income 850 non-null float64 ← 缺失 150 行
# 2 education 920 non-null object ← 缺失 80 行
# 3 gender 1000 non-null object
# dtypes: float64(2), object(2)
# memory usage: 31.3 KB
| info() 输出字段 | 缺失值检测价值 |
|---|---|
| RangeIndex | 总行数,作为缺失计算的基准 |
| Non-Null Count | 每列实际非缺失数量,与总行数对比即得缺失数 |
| Dtype | 数据类型影响缺失值插补策略(数值 vs 类别) |
| memory usage | 缺失值可能占用内存,object 类型尤其明显 |
注意:
info() 默认只显示前 30 列,如果数据集列数较多,使用 df.info(verbose=True, show_counts=True) 确保所有列都输出。
4.3 数值列的“统计摘要”:describe()
describe() 默认只对数值列生成描述性统计,包括计数、均值、标准差、四分位数等。其中的 count 行直接反映了该列的非缺失数量,与 info() 的 Non-Null Count 一致。
缺失值视角的 describe() 解读:
df.describe()
# 输出示例(部分):
# age income
# count 1000.000 850.000 ← income 只有 850 个非缺失值
# mean 38.500 75000.000
# std 12.300 25000.000
# min 18.000 15000.000
# 25% 28.000 55000.000
# 50% 37.000 72000.000
# 75% 48.000 92000.000
# max 65.000 200000.000
| describe() 统计量 | 与缺失值的关系 |
|---|---|
| count | 非缺失数量,直接反映缺失程度 |
| mean / std | 缺失值插补(如均值填充)的参考值 |
| min / max | 判断插补值是否超出合理范围 |
| 25% / 50% / 75% | 中位数填充、分位数填充的依据 |
扩展用法:使用
df.describe(include='object') 可以查看类别列的统计信息,包括 count、unique、top、freq,帮助判断类别列是否存在缺失。
4.4 四类方法对比总结
| 方法 | 输出类型 | 缺失检测能力 | 适用场景 |
|---|---|---|---|
isnull() |
布尔矩阵 | 逐元素精确检测 | 筛选缺失行、计算缺失率、可视化前检查 |
notnull() |
布尔矩阵 | 逐元素精确检测(反向) | 筛选完整行、与 all() 组合 |
info() |
文本摘要 | 列级非空计数 + 数据类型 | 快速概览、数据清洗前诊断 |
describe() |
统计 DataFrame | 数值列非空计数 + 分布统计 | 数值列缺失评估、插补参数参考 |
4.5 实战:构建缺失值诊断报告
将上述方法组合,可以快速生成一份结构化的缺失值诊断报告,为后续插补策略提供决策依据。
完整诊断代码:
def missing_diagnosis(df):
"""生成缺失值诊断报告"""
report = pd.DataFrame({
'缺失数量': df.isnull().sum(),
'缺失比例': df.isnull().mean().round(4),
'数据类型': df.dtypes,
'非空数量': df.notnull().sum()
})
report['缺失等级'] = pd.cut(
report['缺失比例'],
bins=[-0.001, 0.01, 0.05, 0.2, 1.0],
labels=['极少(<1%)', '少量(1-5%)', '中等(5-20%)', '大量(>20%)']
)
return report.sort_values('缺失比例', ascending=False)
# 使用示例
diagnosis = missing_diagnosis(df)
print(diagnosis)
| 缺失等级 | 建议策略 |
|---|---|
| 极少 (<1%) | 直接删除缺失行,或简单填充(均值/众数) |
| 少量 (1-5%) | 均值/中位数/众数填充,或模型预测填充 |
| 中等 (5-20%) | 需要谨慎选择插补方法,考虑多重插补或 KNN |
| 大量 (>20%) | 评估该特征是否保留,或使用高级插补方法 |
最佳实践:在开始任何插补操作之前,先运行
missing_diagnosis() 函数,将结果保存为 CSV 或直接打印,作为特征工程文档的一部分。这有助于团队理解数据质量,并为后续模型性能分析提供基线。