
在数据分析和可视化过程中,我们经常需要对同一数据集进行多种聚合操作,例如计算分组的总和与平均值,并希望将这些结果在一个图表中进行比较。直接尝试将两个独立的 groupby().plot.barh() 调用合并到一个图表中通常会遇到挑战,因为它们生成的是独立的图表实例,并且数据结构可能不兼容。本教程将提供一种结构化的方法来解决这个问题,通过数据预处理和matplotlib的灵活绘图功能,实现组合条形图的创建。
核心思路:数据合并与统一绘图
解决此问题的关键在于:
- 独立聚合并规范化数据: 分别执行 groupby() 聚合操作,并将结果转换为标准DataFrame,确保分组键作为可访问的列。
- 合并数据: 将两个聚合结果DataFrame基于共同的分组键进行合并,形成一个包含所有聚合指标的统一DataFrame。
- 统一绘图: 使用Matplotlib的 plt.subplots() 创建一个图表和坐标轴对象,然后利用合并后的DataFrame在同一个坐标轴上绘制组合条形图。
详细步骤与示例代码
假设我们有一个名为 day_df 的DataFrame,其中包含 yr (年份), season (季节), weathersit (天气情况) 等分组字段,以及 cnt (计数) 字段。我们的目标是可视化不同分组下 cnt 的总和与平均值。
首先,导入必要的库:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 假设 day_df 已经加载并包含数据
# 例如,创建一个模拟数据用于演示
data = {
'yr': [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
'season': [1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2],
'weathersit': [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2],
'cnt': [100, 150, 200, 250, 300, 350, 400, 450, 120, 180, 220, 280, 330, 380, 430, 480]
}
day_df = pd.DataFrame(data)1. 数据聚合与规范化
分别计算 cnt 的平均值和总和,并使用 reset_index() 将分组键从索引转换为常规列。
立即学习“Python免费学习笔记(深入)”;
# 计算每个分组的平均值
day_mean_dataframe = day_df.groupby(by=["yr", "season", "weathersit"]).agg({"cnt": "mean"}).reset_index()
# 计算每个分组的总和
day_sum_dataframe = day_df.groupby(by=["yr", "season", "weathersit"]).agg({"cnt": "sum"}).reset_index()
print("Mean DataFrame Head:")
print(day_mean_dataframe.head())
print("\nSum DataFrame Head:")
print(day_sum_dataframe.head())reset_index() 是一个关键步骤,它将 groupby 操作后生成的多层索引转换回扁平的DataFrame结构,使得 yr, season, weathersit 成为普通的列,便于后续的合并操作。
2. 合并数据帧
使用 pd.merge() 函数将两个聚合后的DataFrame合并。合并时,指定 on 参数为共同的分组键,并使用 suffixes 参数为相同列名的聚合结果添加不同的后缀,以避免列名冲突。
merged_df = pd.merge(day_mean_dataframe, day_sum_dataframe, on=["yr", "season", "weathersit"], suffixes=('_mean', '_sum'))
print("\nMerged DataFrame Head:")
print(merged_df.head())现在,merged_df 包含了每个分组的 cnt_mean 和 cnt_sum,数据已经准备好进行统一绘图。
3. 绘制组合条形图
我们将展示两种常见的组合条形图:垂直条形图和水平条形图。
3.1 绘制垂直组合条形图
# 创建图表和坐标轴对象
fig, ax = plt.subplots(figsize=(14, 7)) # 调整图表大小以适应更多标签
# 确定每个分组条形的位置
r1 = np.arange(len(merged_df)) # 为每个分组创建一个基准位置
width1 = 0.4 # 条形的宽度
# 绘制平均值条形
bars_mean = ax.bar(r1 - width1/2, merged_df["cnt_mean"], width=width1, label='平均值 (Mean)', color='skyblue')
# 绘制总和条形,位置稍微偏移
bars_sum = ax.bar(r1 + width1/2, merged_df["cnt_sum"], width=width1, label='总和 (Sum)', color='lightcoral')
# 设置X轴刻度标签
# 刻度位置应该在两个条形的中间
ax.set_xticks(r1)
# 组合分组键作为X轴标签
ax.set_xticklabels([f'Yr:{row.yr}, Sea:{row.season}, Wea:{row.weathersit}' for _, row in merged_df.iterrows()], rotation=90, ha='right')
# 添加图例、标题和轴标签
ax.legend()
ax.set_xlabel("分组条件 (年, 季节, 天气情况)")
ax.set_ylabel("计数")
ax.set_title("不同分组下计数的平均值与总和 (垂直条形图)")
plt.tight_layout() # 自动调整布局,防止标签重叠
plt.show()3.2 绘制水平组合条形图
水平条形图在分组标签较长时特别有用,可以避免标签重叠。
# 创建图表和坐标轴对象
fig, ax = plt.subplots(figsize=(14, 8)) # 调整图表大小
# 确定每个分组条形的位置
r1 = np.arange(len(merged_df)) # 为每个分组创建一个基准位置
height1 = 0.4 # 条形的高度 (对于水平条形图)
# 绘制平均值条形
bars_mean_h = ax.barh(r1 - height1/2, merged_df["cnt_mean"], height=height1, label='平均值 (Mean)', color='skyblue')
# 绘制总和条形,位置稍微偏移
bars_sum_h = ax.barh(r1 + height1/2, merged_df["cnt_sum"], height=height1, label='总和 (Sum)', color='lightcoral')
# 设置Y轴刻度标签
# 刻度位置应该在两个条形的中间
ax.set_yticks(r1)
# 组合分组键作为Y轴标签
ax.set_yticklabels([f'Yr:{row.yr}, Sea:{row.season}, Wea:{row.weathersit}' for _, row in merged_df.iterrows()])
# 添加图例、标题和轴标签
ax.legend()
ax.set_xlabel("计数")
ax.set_ylabel("分组条件 (年, 季节, 天气情况)")
ax.set_title("不同分组下计数的平均值与总和 (水平条形图)")
plt.tight_layout() # 自动调整布局
plt.show()注意事项
- reset_index() 的重要性: 在 groupby() 之后,聚合列会成为新的索引。使用 reset_index() 可以将这些索引转换为普通列,使得它们可以在 pd.merge() 中作为 on 参数进行合并,并且方便在绘图时作为标签或数据点。
- pd.merge() 的应用: 这是将不同聚合结果整合到一起的关键步骤。确保 on 参数指定了所有用于分组的列,并且 suffixes 参数用于区分合并后相同名称的聚合列。
- Matplotlib subplots(): 推荐使用 plt.subplots() 来创建图表 (fig) 和坐标轴 (ax) 对象,这样可以更灵活地控制图表的各个元素。
- 条形位置计算: 在绘制组合条形图时,需要巧妙地计算每个条形的位置 (r1, r1 + width1 或 r1 - width1/2, r1 + width1/2),确保它们并排显示且中心对齐。
- 标签与可读性: 当分组标签较长时,尤其是在垂直条形图中,使用 rotation=90 和 ha='right' (或 ha='center') 可以改善标签的可读性。对于水平条形图,通常标签会更清晰。plt.tight_layout() 可以自动调整图表布局,防止标签和标题重叠。
- 自定义: Matplotlib 提供了丰富的自定义选项,可以调整条形颜色、边框、图例、标题、轴标签等,以使图表更具表现力。
总结
通过将独立的 groupby 聚合结果进行规范化、合并,并利用Matplotlib的 bar() 或 barh() 函数在同一坐标轴上进行绘制,我们可以有效地创建出清晰、专业的组合条形图。这种方法不仅解决了直接合并 plot.barh() 结果的难题,也为更复杂的多指标可视化提供了坚实的基础。掌握这种数据处理和绘图技巧,将大大提升数据分析和报告的效率与质量。










