Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

参考:matplotlib boxplot by group

MatplotlibPython 中最流行的数据可视化库之一,它提供了丰富的绘图功能,其中箱线图(boxplot)是一种非常有用的统计图表。本文将详细介绍如何使用 Matplotlib 绘制分组箱线图,帮助您更好地理解和展示分组数据的分布情况。

1. 箱线图简介

箱线图,也称为盒须图,是一种用于显示一组数据分布情况的统计图表。它可以直观地展示数据的中位数、四分位数、异常值等统计信息。在数据分析中,箱线图常用于比较不同组别或类别的数据分布。

以下是一个简单的箱线图示例:

import matplotlib.pyplot as plt
import numpy as np

# 生成示例数据
data = np.random.randn(100)

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制箱线图
ax.boxplot(data)

# 设置标题和标签
ax.set_title('Simple Boxplot - how2matplotlib.com')
ax.set_xlabel('Group')
ax.set_ylabel('Value')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个示例展示了如何绘制一个基本的箱线图。我们使用 numpy 生成随机数据,然后通过 boxplot() 函数绘制箱线图。图中的箱体表示数据的四分位范围,中间的线表示中位数,须线表示数据的范围,而点则表示异常值。

2. 分组箱线图的基本概念

分组箱线图是将多组数据的箱线图绘制在同一个坐标系中,以便直观地比较不同组别的数据分布。这种图表特别适合用于比较多个类别或组别的数据特征。

下面是一个简单的分组箱线图示例:

import matplotlib.pyplot as plt
import numpy as np

# 生成示例数据
group1 = np.random.normal(0, 1, 100)
group2 = np.random.normal(2, 1.5, 100)
group3 = np.random.normal(-1, 2, 100)

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制分组箱线图
ax.boxplot([group1, group2, group3], labels=['Group 1', 'Group 2', 'Group 3'])

# 设置标题和标签
ax.set_title('Grouped Boxplot - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

在这个例子中,我们创建了三组具有不同均值和标准差的正态分布数据,然后使用 boxplot() 函数将它们绘制在同一个图表中。这样我们可以直观地比较三组数据的分布情况。

3. 数据准备和格式化

在绘制分组箱线图之前,我们需要正确地准备和格式化数据。通常,数据可以以列表的列表、字典或 pandas DataFrame 的形式组织。

3.1 使用列表的列表

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制箱线图
ax.boxplot(data)

# 设置标题和标签
ax.set_title('Boxplot with List of Lists - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

在这个例子中,我们使用列表推导式创建了一个包含三个子列表的列表,每个子列表代表一组数据。

3.2 使用字典

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
data = {f'Group {i}': np.random.normal(i, 1, 100) for i in range(1, 4)}

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制箱线图
ax.boxplot(data.values())

# 设置标题和标签
ax.set_title('Boxplot with Dictionary - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')
ax.set_xticklabels(data.keys())

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子展示了如何使用字典来组织数据。字典的键作为组名,值作为每组的数据。

3.3 使用 pandas DataFrame

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

# 创建 DataFrame
df = pd.DataFrame({
    'Group A': np.random.normal(0, 1, 100),
    'Group B': np.random.normal(2, 1.5, 100),
    'Group C': np.random.normal(-1, 2, 100)
})

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制箱线图
df.boxplot(ax=ax)

# 设置标题和标签
ax.set_title('Boxplot with pandas DataFrame - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

使用 pandas DataFrame 是处理和可视化分组数据的一种非常方便的方式。每列代表一个组,列名自动成为 x 轴的标签。

4. 自定义箱线图样式

Matplotlib 提供了多种方式来自定义箱线图的样式,使其更加美观和信息丰富。

4.1 修改箱体颜色和透明度

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制自定义样式的箱线图
bplot = ax.boxplot(data, patch_artist=True)

# 设置箱体颜色和透明度
colors = ['lightblue', 'lightgreen', 'lightpink']
for patch, color in zip(bplot['boxes'], colors):
    patch.set_facecolor(color)
    patch.set_alpha(0.7)

# 设置标题和标签
ax.set_title('Customized Boxplot - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

在这个例子中,我们使用 patch_artist=True 参数来允许自定义箱体的颜色。然后,我们通过设置 facecoloralpha 属性来修改箱体的颜色和透明度。

4.2 修改线条样式

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制自定义线条样式的箱线图
bplot = ax.boxplot(data, linestyle='--', linewidth=2)

# 设置中位数线的样式
for median in bplot['medians']:
    median.set_color('red')
    median.set_linewidth(3)

# 设置标题和标签
ax.set_title('Boxplot with Custom Line Styles - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 显示图形
plt.show()

这个例子展示了如何修改箱线图的线条样式。我们使用虚线样式和加粗的线宽,并特别强调了中位数线的颜色和宽度。

4.3 添加数据点

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
data = [np.random.normal(0, std, 30) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制箱线图并添加数据点
bplot = ax.boxplot(data, patch_artist=True, showfliers=False)
for i, d in enumerate(data):
    y = d
    x = np.random.normal(i+1, 0.04, len(y))
    ax.scatter(x, y, alpha=0.5)

# 设置标题和标签
ax.set_title('Boxplot with Data Points - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子展示了如何在箱线图上添加原始数据点。我们使用 scatter() 函数在每个箱体旁边绘制散点图,以显示数据的分布情况。

5. 处理分类数据

有时,我们需要根据分类变量来绘制箱线图。Matplotlib 可以很好地处理这种情况。

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

# 创建示例数据
np.random.seed(42)
df = pd.DataFrame({
    'group': np.repeat(['A', 'B', 'C'], 100),
    'value': np.concatenate([
        np.random.normal(0, 1, 100),
        np.random.normal(2, 1.5, 100),
        np.random.normal(-1, 2, 100)
    ])
})

# 创建图形和坐标轴
fig, ax = plt.subplots()

# 绘制箱线图
ax.boxplot([df[df['group'] == g]['value'] for g in ['A', 'B', 'C']])

# 设置标题和标签
ax.set_title('Boxplot for Categorical Data - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')
ax.set_xticklabels(['A', 'B', 'C'])

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

在这个例子中,我们创建了一个包含分类变量 ‘group’ 和数值变量 ‘value’ 的 DataFrame。然后,我们根据分类变量对数据进行分组,并为每个组绘制箱线图。

6. 多变量箱线图

当我们需要比较多个变量在不同组别间的分布时,多变量箱线图非常有用。

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

# 创建示例数据
np.random.seed(42)
df = pd.DataFrame({
    'group': np.repeat(['A', 'B', 'C'], 100),
    'var1': np.random.normal(0, 1, 300),
    'var2': np.random.normal(2, 1.5, 300),
    'var3': np.random.normal(-1, 2, 300)
})

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制多变量箱线图
positions = [1, 2, 3, 5, 6, 7, 9, 10, 11]
variables = ['var1', 'var2', 'var3']
colors = ['lightblue', 'lightgreen', 'lightpink']

for i, var in enumerate(variables):
    bp = ax.boxplot([df[df['group'] == g][var] for g in ['A', 'B', 'C']],
                    positions=positions[i*3:(i+1)*3],
                    patch_artist=True)

    for patch in bp['boxes']:
        patch.set_facecolor(colors[i])

# 设置标题和标签
ax.set_title('Multivariate Boxplot - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')
ax.set_xticks([2, 6, 10])
ax.set_xticklabels(['A', 'B', 'C'])

# 添加图例
ax.legend([bp['boxes'][0] for bp in ax.get_children() if isinstance(bp, dict)],
          variables, loc='upper right')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子展示了如何创建多变量箱线图。我们为每个变量绘制了三个组的箱线图,并使用不同的颜色来区分变量。

7. 水平箱线图

有时,水平方向的箱线图可能更适合某些数据的展示,特别是当组名较长时。

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
data = [np.random.normal(0, std, 100) for std in range(1, 6)]
labels = ['Group A with long name', 'Group B with longer name',
          'Group C with even longer name', 'Group D', 'Group E']

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制水平箱线图
ax.boxplot(data, vert=False)

# 设置标题和标签
ax.set_title('Horizontal Boxplot - how2matplotlib.com')
ax.set_xlabel('Values')
ax.set_yticklabels(labels)

# 调整布局
plt.tight_layout()

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

在这个例子中,我们使用 vert=False 参数来创建水平方向的箱线图。这种布局特别适合展示具有长标签的分组数据。

8. 添加统计信息

为了使箱线图更加信息丰富,我们可以在图表中添加一些统计信息,如均值或样本量。

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制箱线图
bp = ax.boxplot(data)

# 添加均值点
means = [np.mean(d) for d in data]
ax.scatter(range(1, len(data) + 1), means, color='red', marker='o', s=50, zorder=3)

# 添加样本量标签
for i, d in enumerate(data):
    ax.text(i + 1, ax.get_ylim()[1], f'n={len(d)}', 
            horizontalalignment='center', verticalalignment='bottom')

# 设置标题和标签
ax.set_title('Boxplot with Statistics - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 添加图例
ax.legend([bp['medians'][0], bp['means'][0]], ['Median', 'Mean'], loc='lower right')

# 显示图形
plt.show()

在这个例子中,我们添加了红色的点来表示每组数据的均值,并在每个箱子上方标注了样本量。这些额外的信息可以帮助读者更好地理解数据的分布情况。

9. 处理异常值

箱线图的一个重要特性是它可以显示异常值。但有时,我们可能想要调整异常值的显示方式或完全隐藏它们。

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
np.random.seed(42)
data = [np.random.normal(0, 1, 100) for _ in range(3)]
# 添加一些异常值
data[0] = np.append(data[0], [5, 6, -5, -6])
data[1] = np.append(data[1], [7, 8, -7, -8])
data[2] = np.append(data[2], [9, 10, -9, -10])

# 创建图形和坐标轴
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))

# 绘制默认箱线图
ax1.boxplot(data)
ax1.set_title('Default Boxplot\nhow2matplotlib.com')

# 绘制自定义异常值的箱线图
ax2.boxplot(data, flierprops=dict(marker='o', markerfacecolor='red', markersize=8,
                                  linestyle='none'))
ax2.set_title('Customized Outliers\nhow2matplotlib.com')

# 设置标签
for ax in (ax1, ax2):
    ax.set_xlabel('Groups')
    ax.set_ylabel('Values')

# 调整布局
plt.tight_layout()

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子展示了如何自定义异常值的显示方式。在右侧的图表中,我们将异常值标记为红色的圆点,使其更加醒目。

10. 分组箱线图与其他图表的组合

有时,将箱线图与其他类型的图表结合使用可以提供更全面的数据视图。

10.1 箱线图与散点图的组合

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制箱线图
bp = ax.boxplot(data, positions=[1, 2, 3], widths=0.6)

# 添加散点图
for i, d in enumerate(data):
    y = d
    x = np.random.normal(i+1, 0.04, len(y))
    ax.scatter(x, y, alpha=0.4)

# 设置标题和标签
ax.set_title('Boxplot with Scatter Plot - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['Group A', 'Group B', 'Group C'])

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子展示了如何将箱线图与散点图结合,以同时显示数据的分布和个别数据点。

10.2 箱线图与小提琴图的组合

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制小提琴图
parts = ax.violinplot(data, positions=[1, 2, 3], showmeans=False, showmedians=False, showextrema=False)

for pc in parts['bodies']:
    pc.set_facecolor('#D43F3A')
    pc.set_edgecolor('black')
    pc.set_alpha(0.7)

# 绘制箱线图
bp = ax.boxplot(data, positions=[1, 2, 3], widths=0.15, patch_artist=True)

for box in bp['boxes']:
    box.set_facecolor('white')
    box.set_edgecolor('black')

# 设置标题和标签
ax.set_title('Boxplot with Violin Plot - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['Group A', 'Group B', 'Group C'])

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子展示了如何将箱线图与小提琴图结合。小提琴图可以更好地展示数据的分布密度,而箱线图则提供了关键的统计信息。

11. 动态更新的箱线图

在某些情况下,我们可能需要创建一个可以动态更新的箱线图,例如用于实时数据可视化。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation

# 准备初始数据
data = [np.random.normal(0, 1, 100) for _ in range(3)]

# 创建图形和坐标轴
fig, ax = plt.subplots()
bp = ax.boxplot(data)

# 更新函数
def update(frame):
    # 更新数据
    for i in range(3):
        data[i] = np.append(data[i][1:], np.random.normal(0, 1))

    # 更新箱线图
    for i, box in enumerate(bp['boxes']):
        y = data[i]
        box.set_ydata([np.percentile(y, 25), np.percentile(y, 25),
                       np.percentile(y, 75), np.percentile(y, 75)])

    for i, median in enumerate(bp['medians']):
        median.set_ydata([np.median(data[i]), np.median(data[i])])

    for i, whisker in enumerate(bp['whiskers']):
        if i % 2 == 0:
            whisker.set_ydata([np.min(data[i//2]), np.percentile(data[i//2], 25)])
        else:
            whisker.set_ydata([np.percentile(data[i//2], 75), np.max(data[i//2])])

    return bp

# 创建动画
ani = FuncAnimation(fig, update, frames=200, interval=50, blit=False)

# 设置标题和标签
ax.set_title('Dynamic Boxplot - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 显示动画
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子创建了一个动态更新的箱线图。每次更新时,我们移除每组数据的最旧的值,并添加一个新的随机值,然后重新计算并更新箱线图的各个组成部分。

12. 保存和导出箱线图

在创建完箱线图后,我们通常需要将其保存为图像文件或导出为其他格式。

import matplotlib.pyplot as plt
import numpy as np

# 准备数据
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制箱线图
ax.boxplot(data)

# 设置标题和标签
ax.set_title('Boxplot for Saving - how2matplotlib.com')
ax.set_xlabel('Groups')
ax.set_ylabel('Values')

# 保存为PNG文件
plt.savefig('boxplot_example.png', dpi=300, bbox_inches='tight')

# 保存为PDF文件
plt.savefig('boxplot_example.pdf', bbox_inches='tight')

# 保存为SVG文件
plt.savefig('boxplot_example.svg', bbox_inches='tight')

# 显示图形
plt.show()

Output:

Matplotlib 分组箱线图绘制指南:如何使用 boxplot 展示分组数据

这个例子展示了如何将箱线图保存为不同的文件格式。savefig() 函数允许我们指定文件名和格式。dpi 参数控制图像的分辨率,而 bbox_inches='tight' 确保图表的所有部分都被包含在保存的文件中。

总结

本文详细介绍了如何使用 Matplotlib 创建分组箱线图,涵盖了从基础概念到高级技巧的多个方面。我们学习了如何准备和格式化数据、自定义箱线图样式、处理分类数据和多变量数据、添加统计信息、处理异常值、结合其他图表类型,以及创建动态更新的箱线图。

通过掌握这些技巧,您可以创建出既信息丰富又视觉吸引的分组箱线图,有效地展示和比较不同组别的数据分布。记住,好的数据可视化不仅要准确传达信息,还要易于理解和解释。在实际应用中,根据您的具体需求和数据特征,灵活运用这些技巧来创建最适合您的箱线图。

最后,不要忘记探索 Matplotlib 的其他功能和图表类型,它们可能会为您的数据分析和可视化工作带来新的灵感和可能性。持续学习和实践将帮助您成为数据可视化的专家。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程