4、缺失值可视化基础:使用Matplotlib/Seaborn绘制缺失值热力图、缺失值条形图

在特征缺失巡检中,数值统计只能告诉我们“有多少缺失”,而可视化能揭示“缺失发生在哪里”以及“缺失之间是否存在关联”。本章将系统讲解如何利用 Matplotlib 和 Seaborn 绘制两种最核心的缺失值诊断图:缺失值热力图与缺失值条形图。

4.1 为什么需要缺失值可视化?

单纯打印 df.isnull().sum() 只能获得一维统计量,无法回答以下关键问题:

  • 缺失分布模式:缺失是随机散布,还是集中在某些行/列?
  • 缺失关联性:特征 A 的缺失是否伴随特征 B 的缺失?
  • 缺失比例排序:哪些特征缺失最严重,需要优先处理?

可视化将上述问题转化为直观的图形信号,帮助数据科学家在几秒内锁定数据质量风险点。

4.2 缺失值条形图:快速掌握缺失比例排序

缺失值条形图(Missing Value Bar Chart)以条形长度展示每个特征的缺失数量或缺失率,通常按缺失比例降序排列,便于识别“缺失重灾区”。

4.2.1 核心绘制逻辑

  1. 计算每个特征的缺失值数量:df.isnull().sum()
  2. 转换为缺失率(可选):df.isnull().mean() * 100
  3. 按缺失值降序排序
  4. 使用 Matplotlib 的 barh 或 Seaborn 的 barplot 绘制水平条形图

4.2.2 代码示例

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

# 构造示例数据
np.random.seed(42)
data = pd.DataFrame({
    'feature_a': np.random.randn(100),
    'feature_b': np.random.randn(100),
    'feature_c': np.random.randn(100),
    'feature_d': np.random.randn(100),
    'feature_e': np.random.randn(100)
})
# 人为制造缺失
data.loc[0:19, 'feature_a'] = np.nan
data.loc[5:34, 'feature_c'] = np.nan
data.loc[10:24, 'feature_e'] = np.nan
data.loc[40:49, 'feature_b'] = np.nan

# 计算缺失数量并排序
missing_counts = data.isnull().sum()
missing_counts = missing_counts[missing_counts > 0].sort_values(ascending=True)

# 绘制水平条形图
plt.figure(figsize=(8, 4))
sns.set_style("whitegrid")
bars = plt.barh(missing_counts.index, missing_counts.values, 
                color='#3498db', edgecolor='#2980b9')
plt.xlabel('缺失数量', fontsize=12)
plt.title('缺失值条形图 — 特征缺失数量排序', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()
实践建议:当特征数量超过 20 个时,优先使用水平条形图(barh),避免特征名称被截断或重叠。缺失率超过 50% 的特征应标记为高风险,在后续巡检中重点分析。

4.3 缺失值热力图:揭示缺失关联模式

缺失值热力图(Missing Value Heatmap)将数据集的缺失状态编码为二元矩阵(1=缺失,0=存在),并用颜色深浅表示缺失密度。它能够直观展示:

  • 缺失的“条带”效应:某些行或列是否集中缺失
  • 特征间缺失共现:两个特征的缺失区域是否高度重叠
  • 缺失的随机性:理想随机缺失(MCAR)应呈现均匀散布的噪点

4.3.1 核心绘制逻辑

  1. 生成缺失指示矩阵:df.isnull().astype(int)
  2. 转置矩阵使特征为行、样本为列(便于观察特征间关系)
  3. 使用 Seaborn 的 heatmap 绘制,配色使用深色表示缺失
  4. 可配合 cbar=False 关闭色标,或使用 cmap 自定义配色

4.3.2 代码示例

# 生成缺失指示矩阵并转置
missing_matrix = data.isnull().astype(int).T

plt.figure(figsize=(12, 5))
sns.heatmap(missing_matrix, 
            cmap=['#f0f8ff', '#e74c3c'],  # 浅蓝=存在,红色=缺失
            cbar=False,
            xticklabels=False,            # 样本量多时隐藏x轴标签
            yticklabels=True,
            linewidths=0.5,
            linecolor='#f0f8ff')
plt.title('缺失值热力图 — 特征缺失分布模式', fontsize=14, fontweight='bold')
plt.xlabel('样本索引', fontsize=12)
plt.ylabel('特征名称', fontsize=12)
plt.tight_layout()
plt.show()
注意:当数据集样本量超过 1000 时,热力图的 x 轴标签会严重重叠。建议设置 xticklabels=False 或使用 xticklabels=50 每隔 50 个样本显示一个刻度。对于超大规模数据(>10000 行),可先对缺失矩阵进行行采样或使用分块渲染。

4.4 两种可视化方法的对比与选型

对比维度 缺失值条形图 缺失值热力图
核心目标 展示缺失数量的排序与比例 展示缺失的空间分布与关联
适用场景 快速识别缺失最严重的特征 分析缺失模式、缺失共现、系统性缺失
数据规模 特征数 < 50 时效果最佳 样本数 < 2000 时视觉清晰
信息密度 低(仅一维统计量) 高(二维矩阵 + 颜色编码)
缺失关联判断 无法判断 可直接观察缺失条带与共现
推荐库 Matplotlib / Seaborn Seaborn(heatmap)

4.5 缺失值可视化流程架构

下图展示了从原始数据到可视化诊断的完整流程,以及两种图形在巡检管线中的定位。

缺失值可视化流程架构 原始数据集 缺失检测 is null() 缺失统计 sum() / mean() 缺失指示矩阵 astype(int) 缺失值条形图 缺失值热力图 条形图侧重“缺失数量排序”,热力图侧重“缺失空间分布与关联”,两者互补使用

4.6 进阶技巧:缺失率阈值线与双轴图

在实际巡检中,我们经常需要在条形图上叠加一条缺失率阈值线(如 20%、50%),快速区分可容忍缺失与高风险缺失。

# 计算缺失率并排序
missing_rate = data.isnull().mean() * 100
missing_rate = missing_rate[missing_rate > 0].sort_values(ascending=True)

fig, ax = plt.subplots(figsize=(8, 4))
bars = ax.barh(missing_rate.index, missing_rate.values, 
               color='#3498db', edgecolor='#2980b9')
ax.set_xlabel('缺失率 (%)', fontsize=12)
ax.set_title('缺失率条形图 — 含 20% 阈值线', fontsize=14, fontweight='bold')

# 添加阈值线
ax.axvline(x=20, color='#e74c3c', linestyle='--', linewidth=2, label='20% 阈值')
ax.legend(loc='lower right')
plt.tight_layout()
plt.show()
巡检经验:在 LightGBM 建模场景中,缺失率超过 50% 的特征通常不建议直接入模,除非缺失本身具有业务含义(如“用户未填写”代表某种行为模式)。条形图配合阈值线能帮助团队在特征筛选会议上快速达成共识。

4.7 本章小结

  • 缺失值条形图:一维排序视图,适合快速定位缺失重灾区,推荐与缺失率阈值线结合使用。
  • 缺失值热力图:二维矩阵视图,适合发现缺失模式、缺失共现与系统性缺失问题。
  • 选型原则:特征数少、关注排序用条形图;样本量适中、关注分布用热力图;两者结合可覆盖 90% 的缺失诊断场景。
  • 代码规范:使用 isnull().sum() 与 isnull().mean() 作为数据准备入口,Seaborn 的 heatmap 与 Matplotlib 的 barh 作为主力绘图函数。