4. 缺失值检测:缺失值类型与统计可视化

缺失值是数据质量检查中最常见的问题之一。Python 中缺失值的表现形式多样,检测方法也需区分不同数据类型。本节系统梳理缺失值的类型、检测方法、统计汇总与可视化技术。

4.1 缺失值类型:NaN / None / 空字符串

在 Python 数据生态中,缺失值并非只有一种形态。下表列出三种常见缺失值类型及其特征:

类型 Python 表示 所属库 isnull() 识别 典型场景
NaN float('nan') / np.nan NumPy / pandas ✅ 是 数值列缺失、计算溢出
None None Python 原生 ✅ 是 对象列缺失、函数无返回值
空字符串 '' / " " Python 原生 ❌ 否 文本字段未填写、导入空白
⚠️ 常见陷阱:空字符串 '' 不会被 isnull() 检测为缺失值。如果业务上将空字符串视为缺失,必须先用 .replace('', np.nan) 或条件筛选进行转换。

4.2 isnull() 与 isna() 方法

pandas 提供两个功能完全等价的方法:isnull() 和 isna()。两者底层调用同一函数,返回布尔型 DataFrame 或 Series,True 表示该位置为缺失值。

基本用法:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'A': [1, 2, np.nan, 4],
    'B': [None, 'b', 'c', 'd'],
    'C': ['', 'x', 'y', 'z']
})

# 检测缺失值(NaN 和 None 会被识别)
print(df.isnull())

# 等价写法
print(df.isna())

输出示例:

       A      B      C
0  False   True  False
1  False  False  False
2   True  False  False
3  False  False  False
💡 建议:团队中统一使用 isna() 或 isnull() 均可,但不要混用。推荐 isna(),因为 NA 是 pandas 官方对缺失值的标准术语。

4.3 缺失值统计:sum / mean

对 isna() 的结果进行聚合统计,可以快速掌握数据集的缺失概况。

常用统计方法:

方法 含义 代码示例
sum() 每列缺失值个数 df.isna().sum()
mean() 每列缺失值比例 df.isna().mean()
sum(axis=1) 每行缺失值个数 df.isna().sum(axis=1)
any(axis=1) 是否存在至少一个缺失 df.isna().any(axis=1)

完整统计示例:

# 缺失值个数统计
missing_count = df.isna().sum()
print("缺失值个数:\n", missing_count)

# 缺失值比例统计
missing_ratio = df.isna().mean()
print("\n缺失值比例:\n", missing_ratio)

# 筛选包含缺失的行
rows_with_na = df[df.isna().any(axis=1)]
print("\n包含缺失的行:\n", rows_with_na)

输出示例:

缺失值个数:
A    1
B    1
C    0
dtype: int64

缺失值比例:
A    0.25
B    0.25
C    0.00
dtype: float64

包含缺失的行:
     A    B C
0  1.0  NaN 
2  NaN    c y

4.4 缺失值可视化:缺失值热力图

热力图可以直观展示缺失值在数据集中的分布模式,帮助发现系统性缺失或随机缺失。最常用的工具是 seaborn.heatmap() 结合 isna()。

基础热力图代码:

import seaborn as sns
import matplotlib.pyplot as plt

# 绘制缺失值热力图
plt.figure(figsize=(10, 6))
sns.heatmap(df.isna(), cbar=False, cmap='viridis', yticklabels=False)
plt.title('缺失值热力图', fontsize=14)
plt.xlabel('列名')
plt.ylabel('行索引')
plt.tight_layout()
plt.show()

热力图解读要点:

  • 黄色/亮色块:表示该位置存在缺失值
  • 紫色/暗色块:表示该位置数据完整
  • 整列亮色:该列几乎全部缺失,考虑删除
  • 水平亮条:某行多个字段同时缺失,可能是记录异常
  • 对角亮线:可能存在数据录入时的系统性偏移
📊 进阶技巧:对于大型数据集,可以抽样绘制热力图,或使用 missingno 库的 matrix() 和 bar() 函数获得更专业的缺失值可视化。
缺失值检测与统计流程 原始 DataFrame isna() / isnull() 空字符串替换 自定义缺失标记 布尔矩阵 (True/False) sum() — 缺失个数 mean() — 缺失比例 缺失值统计报告 + 热力图可视化

4.5 综合检测脚本模板

以下是一个可直接复用的缺失值检测函数,整合了类型识别、统计和可视化:

def missing_value_report(df, plot=True):
    """
    生成缺失值检测报告

    参数:
        df : pandas.DataFrame
        plot : bool, 是否绘制热力图

    返回:
        pd.DataFrame : 缺失值统计表
    """
    # 1. 空字符串转为 NaN(可选)
    df_clean = df.replace(r'^\s*$', np.nan, regex=True)

    # 2. 缺失值统计
    missing_count = df_clean.isna().sum()
    missing_ratio = df_clean.isna().mean()
    missing_report = pd.DataFrame({
        '缺失个数': missing_count,
        '缺失比例': missing_ratio
    })
    missing_report = missing_report[missing_report['缺失个数'] > 0].sort_values('缺失比例', ascending=False)

    # 3. 可视化
    if plot and len(df_clean) > 0:
        plt.figure(figsize=(12, 6))
        sns.heatmap(df_clean.isna(), cbar=False, cmap='viridis', yticklabels=False)
        plt.title('缺失值热力图', fontsize=14)
        plt.tight_layout()
        plt.show()

    return missing_report

# 使用示例
report = missing_value_report(df)
print(report)
💡 生产环境建议:在数据流水线中,将缺失值报告输出为 CSV 文件或写入日志,便于长期监控数据质量变化趋势。
缺失值类型对比与处理策略 NaN (np.nan) 数值列缺失 None 对象列缺失 空字符串 '' 文本字段未填写 检测方法:isna() / isnull() 识别 NaN 和 None;空字符串需额外处理 处理策略:删除 / 填充 / 插值 / 标记 删除缺失行/列 填充(均值/中位数/众数) 插值 / 模型预测 选择策略前,先判断缺失机制:完全随机缺失(MCAR) / 随机缺失(MAR) / 非随机缺失(MNAR)