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 之间),比手动计数除以行数更简洁。
缺失值检测流程:从原始数据到缺失率报告 原始 DataFrame 含 NaN / None isnull() 布尔矩阵 .sum() / .mean() 聚合统计 缺失报告 数量 / 比例 筛选分支 .any(axis=1) → 含缺失行 筛选分支 .all(axis=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 数值列非空计数 + 分布统计 数值列缺失评估、插补参数参考
缺失值检测四方法的分工与协作 原始 DataFrame isnull() 布尔矩阵 notnull() 布尔矩阵(反向) info() 列级非空计数 describe() 统计摘要 协作流程:isnull/notnull 做精确检测 → info 做全局概览 → describe 做数值分布评估 四者结合可覆盖从微观到宏观的完整缺失诊断

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 或直接打印,作为特征工程文档的一部分。这有助于团队理解数据质量,并为后续模型性能分析提供基线。