Matplotlib 可视化大师系列(四):plt.hist() 与 plt.boxplot() - 洞察数据分布

Matplotlib 可视化大师系列博客总览

本系列旨在提供一份系统、全面、深入的 Matplotlib 学习指南。以下是博客列表:

  1. 基础篇plt.plot() - 绘制折线图的利刃
  2. 分布篇plt.scatter() - 探索变量关系的散点图
  3. 比较篇plt.bar()plt.barh() - 清晰对比的柱状图
  4. 统计篇plt.hist()plt.boxplot() - 洞察数据分布
  5. 占比篇plt.pie() - 展示组成部分的饼图
  6. 高级篇plt.imshow() - 绘制矩阵与图像的强大工具
  7. 专属篇绘制误差线 (plt.errorbar())、等高线 (plt.contour()) 等特殊图表
  8. 综合篇在一张图中组合多种图表类型

Matplotlib 可视化大师系列(四):plt.hist() 与 plt.boxplot() - 洞察数据分布

理解数据的分布特征是数据分析的核心环节。直方图(Histogram)和箱线图(Boxplot)是探索数据分布最常用的两种可视化工具。Matplotlib 通过 plt.hist()plt.boxplot() 提供了强大的实现。本文将深入解析这两个函数,帮助你掌握洞察数据分布的艺术。

一、 直方图与箱线图:它们是什么?何时使用?

直方图 (Histogram) 将连续数据划分为一系列区间(称为"bins"),并统计每个区间内数据点的数量(频数)。它展示了单个连续变量的分布形状、中心趋势和离散程度。

  • 适用场景
    • 了解数据的分布形状(是否对称?是单峰还是多峰?)
    • 检查数据是否近似服从某种分布(如正态分布)
    • 发现数据的异常值或间隙
    • 注意:直方图用于连续数据

箱线图 (Boxplot / Box-and-Whisker Plot) 用一种标准化的方式显示数据分布的五个关键统计量:最小值、第一四分位数 (Q1)、中位数 (Q2)、第三四分位数 (Q3) 和最大值。它能有效地显示数据的中位数、离散度、偏度和异常值

  • 适用场景
    • 比较多个组或类别的分布
    • 识别数据中的异常值
    • 直观地比较数据的中位数和散布程度

核心区别

  • 直方图:展示整个分布的形状和密度。
  • 箱线图:总结分布的关键统计量,特别适合比较。

二、 函数原型与核心参数

plt.hist(x, bins=None, ...) - 直方图

plt.hist(x, bins=None, range=None, density=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, **kwargs)

核心参数详解

  1. 数据与分箱:

    • x: 输入数据,一维数组。
    • bins: 最重要的参数,决定如何划分区间。
      • 整数: 指定区间的数量(如 bins=20)。
      • 序列: 指定区间的边界(如 bins=[0, 10, 20, 50, 100])。
      • 字符串: 使用特定算法(如 'auto', 'sturges', 'fd', 'doane', 'scott', 'rice', 'sqrt')。'auto' 通常是一个很好的默认选择。
    • range: tuple (min, max),指定数据范围,超出范围的值将被忽略。默认是 (x.min(), x.max())
  2. 分布显示:

    • density: 如果 True,y轴显示的是密度(频率 / (区间宽度 * 总数量))而不是频数,使得直方图下的总面积等于1。常用于拟合概率分布。
    • cumulative: 如果 True,绘制累积分布直方图
    • histtype: 直方图类型。'bar'(默认,传统条形), 'barstacked'(堆叠), 'step'(生成未填充的线图), 'stepfilled'(生成填充的线图)。
  3. 样式:

    • color: 颜色。
    • alpha: 透明度。
    • rwidth: 柱子的相对宽度(相对于bin的宽度)。
    • orientation: 'vertical'(默认)或 'horizontal'

plt.boxplot(x, ...) - 箱线图

plt.boxplot(x, notch=None, sym=None, vert=None, whis=None, positions=None, widths=None, patch_artist=None, bootstrap=None, usermedians=None, conf_intervals=None, meanline=None, **kwargs)

核心参数详解

  1. 数据:

    • x: 输入数据。可以是一个一维数组(绘制一个箱体),也可以是一个序列或二维数组(每个元素/列绘制一个箱体,用于比较)。
  2. 箱体样式:

    • notch: 如果 True,绘制一个"缺口"箱线图,缺口的宽度表示中位数的置信区间。可用于直观比较中位数的显著性(如果缺口不重叠,中位数可能显著不同)。
    • sym: 指定异常值的标记符号(如 'r+' 表示红色加号)。如果为空字符串 '',则隐藏异常值。
    • vert: 如果 True(默认),箱线图垂直绘制;如果 False,则水平绘制。
    • whis: 定义须线的范围。默认是 1.5
      • 须线: 从箱体(Q1和Q3)延伸出的线,其长度通常为 1.5 * IQR(四分位距,IQR = Q3 - Q1)。须线末端的数据点被认为是异常值
    • widths: 箱体的宽度。
    • patch_artist: 如果 False(默认),箱体是线;如果 True,箱体是填充的多边形,可以使用 facecolor 等参数。
    • meanline: 如果 True,将均值显示为一条线;如果 False(默认),显示为一个点。
  3. 位置:

    • positions: 指定每个箱体的位置。

三、 从入门到精通:代码示例

示例 1:基础直方图与不同参数效果

import matplotlib.pyplot as plt
import numpy as np

# 生成一些正态分布的随机数据
np.random.seed(42)
data = np.random.normal(100, 15, 1000) # 均值=100,标准差=15

fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# 1. 默认直方图
axes[0, 0].hist(data)
axes[0, 0].set_title('Default Histogram (Frequency)')
axes[0, 0].set_ylabel('Frequency')
axes[0, 0].grid(True, linestyle='--', alpha=0.7)

# 2. 密度直方图 (density=True)
axes[0, 1].hist(data, bins=30, density=True, alpha=0.7, color='green', edgecolor='black')
axes[0, 1].set_title('Density Histogram (Area=1)')
axes[0, 1].set_ylabel('Density')
axes[0, 1].grid(True, linestyle='--', alpha=0.7)

# 3. 累积分布直方图 (cumulative=True)
axes[1, 0].hist(data, bins=30, cumulative=True, density=True, color='orange', histtype='step', linewidth=2, label='CDF')
axes[1, 0].set_title('Cumulative Distribution Function (CDF)')
axes[1, 0].set_ylabel('Cumulative Probability')
axes[1, 0].grid(True, linestyle='--', alpha=0.7)
axes[1, 0].legend()

# 4. 水平直方图 (orientation='horizontal')
axes[1, 1].hist(data, bins=30, orientation='horizontal', color='purple', alpha=0.7)
axes[1, 1].set_title('Horizontal Histogram')
axes[1, 1].set_xlabel('Frequency')
axes[1, 1].set_ylabel('Value')
axes[1, 1].grid(True, linestyle='--', alpha=0.7)

plt.tight_layout()
plt.show()

示例 2:基础箱线图与比较

# 生成三组不同的数据用于比较
np.random.seed(42)
data1 = np.random.normal(90, 10, 100)
data2 = np.random.normal(110, 20, 100)
data3 = np.random.normal(80, 5, 100)

# 将数据组合成一个列表
all_data = [data1, data2, data3]
labels = ['Group 1', 'Group 2', 'Group 3']

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# 1. 默认垂直箱线图
box_plot = ax1.boxplot(all_data, labels=labels, patch_artist=True)
ax1.set_title('Standard Vertical Boxplot')
ax1.set_ylabel('Value')
ax1.grid(True, axis='y', linestyle='--', alpha=0.7)

# 2. 水平箱线图
box_plot_h = ax2.boxplot(all_data, labels=labels, vert=False, patch_artist=True)
ax2.set_title('Horizontal Boxplot')
ax2.set_xlabel('Value')
ax2.grid(True, axis='x', linestyle='--', alpha=0.7)

# 为箱体上色 (一个常用的美化技巧)
colors = ['lightblue', 'lightgreen', 'pink']
for patch, color in zip(box_plot['boxes'], colors):
    patch.set_facecolor(color)
for patch, color in zip(box_plot_h['boxes'], colors):
    patch.set_facecolor(color)

plt.tight_layout()
plt.show()

示例 3:解读箱线图与高级特性

# 创建一个带有异常值的数据集
np.random.seed(123)
data_normal = np.random.normal(100, 15, 200)
# 手动添加一些异常值
data_with_outliers = np.append(data_normal, [40, 180, 190])

fig, ax = plt.subplots(figsize=(8, 6))

# 绘制箱线图,并自定义异常值符号
boxprops = dict(linestyle='-', linewidth=2, color='darkblue', facecolor='lightcyan')
flierprops = dict(marker='o', markerfacecolor='red', markersize=8, linestyle='none', markeredgecolor='red')
medianprops = dict(linestyle='-', linewidth=2.5, color='firebrick')
meanpointprops = dict(marker='D', markeredgecolor='black', markerfacecolor='green')

bp = ax.boxplot(data_with_outliers,
                patch_artist=True,
                boxprops=boxprops,
                flierprops=flierprops,
                medianprops=medianprops,
                meanline=False,
                showmeans=True,
                meanprops=meanpointprops)

ax.set_title('Boxplot with Custom Styling and Outliers')
ax.set_ylabel('Value')
ax.grid(True, linestyle='--', alpha=0.7)

# 添加文本注释解释箱线图的各部分
ax.text(1.15, np.percentile(data_with_outliers, 25), 'Q1 (25th %)', va='center', ha='left')
ax.text(1.15, np.median(data_with_outliers), 'Median (Q2, 50th %)', va='center', ha='left')
ax.text(1.15, np.percentile(data_with_outliers, 75), 'Q3 (75th %)', va='center', ha='left')

# 计算IQR和须线
q1, median, q3 = np.percentile(data_with_outliers, [25, 50, 75])
iqr = q3 - q1
lower_whisker = q1 - 1.5 * iqr
upper_whisker = q3 + 1.5 * iqr

ax.text(1.15, lower_whisker, 'Lower Whisker\n(Q1 - 1.5*IQR)', va='center', ha='left')
ax.text(1.15, upper_whisker, 'Upper Whisker\n(Q3 + 1.5*IQR)', va='center', ha='left')
ax.text(0.85, 40, 'Outlier', va='center', ha='right')

plt.tight_layout()
plt.show()

四、 最佳实践与常见陷阱

  1. 直方图最佳实践:

    • 谨慎选择 bin 数量: bin 太少会掩盖细节,太多会产生太多噪声。从 'auto' 开始,然后根据数据特性调整。
    • 使用密度图: 如果你关心的是概率分布而不是绝对计数,使用 density=True
    • 叠加 KDE: 可以在直方图上叠加核密度估计(KDE)图来平滑分布(通常用 Seaborn 的 sns.histplot(..., kde=True) 更方便)。
    • 对齐 bins: 使用 align='left', 'mid'(默认), 或 'right' 来控制柱体相对于 bin 边缘的位置。
  2. 箱线图最佳实践:

    • 用于比较: 箱线图的真正威力在于并排比较多个分布。
    • 解释给观众: 箱线图对不熟悉的观众可能难以理解,确保做好标注或提供图例。
    • 自定义样式: 使用 patch_artist=True 和相关的 *props 参数来创建更美观、更易读的箱线图。
    • 考虑小提琴图: 对于多模态(多个峰)分布,小提琴图(Violin Plot)能提供更多信息,它是箱线图和核密度图的结合。
  3. 常见陷阱:

    • 直方图的 bin 选择偏见: 不同的 bin 数量或边界可以呈现出完全不同的故事。始终尝试多种设置。
    • 误读箱线图: 记住箱线图的"箱体"代表中间50%的数据,不是数据的全部范围。
    • 忽略异常值: 箱线图明确标出了异常值,不要忽视它们。它们可能是数据输入错误,也可能是重要的发现。

五、 总结

plt.hist()plt.boxplot() 是探索数据分布不可或缺的工具。

  • plt.hist(): 揭示整个分布的形状、中心和散布。关注密度频率
    • 核心参数bins, density, cumulative
  • plt.boxplot(): 总结分布的五个关键统计量,高效识别异常值和比较多个分布
    • 核心参数patch_artist, whis, notch, 以及各种 *props 用于样式控制。

掌握这两个函数,你就能从简单的数据描述(如均值、标准差)深入到理解数据的内在结构和特性,这是数据分析和机器学习模型构建的基础。在下一篇文章中,我们将探讨如何展示组成部分,使用 plt.pie() 来绘制饼图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值