You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python或R绘制多层分组的堆叠/并列条形图?

多层分组条形图实现方案(Python + R)

Python 实现(Matplotlib + Seaborn)

思路

先将宽格式数据转为长格式(合并Train/Test score列),通过计算条形位置实现三层分组:最外层按Segment length,中间层按Parameter,最内层按Parameter value,每个值对应并列的Train/Test score条形。

完整代码

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

# 构建目标DataFrame
data = pd.DataFrame({
    'Segment length': [16]*9 + [32]*9,
    'Parameter': ['n_estimators']*3 + ['max_depth']*3 + ['max_features']*3 + 
                 ['n_estimators']*3 + ['max_depth']*3 + ['max_features']*3,
    'Parameter value': [5.0,10.0,15.0,2.0,6.0,10.0,0.1,0.3,0.5,
                        5.0,10.0,15.0,2.0,6.0,10.0,0.1,0.3,0.5],
    'Train score': [0.975414,0.982342,1.0,0.580884,1.0,1.0,1.0,1.0,1.0,
                    0.961905,0.988095,1.0,0.785714,1.0,1.0,1.0,1.0,1.0],
    'Test score': [0.807823,0.756803,0.801020,0.284014,0.824830,0.824830,0.845238,0.845238,0.845238,
                   0.714286,0.857143,0.857143,0.571429,0.857143,0.857143,0.904762,0.904762,0.857143]
})

# 转为长格式,适配分组绘图
melted_data = data.melt(
    id_vars=['Segment length', 'Parameter', 'Parameter value'],
    value_vars=['Train score', 'Test score'],
    var_name='Score type', value_name='Score'
)

# 设置绘图风格与画布大小
sns.set_style("whitegrid")
plt.figure(figsize=(14, 8))

# 定义分组参数与条形尺寸
segment_lengths = melted_data['Segment length'].unique()
parameters = melted_data['Parameter'].unique()
param_values_per_param = melted_data.groupby('Parameter')['Parameter value'].unique()
bar_width = 0.35
segment_gap = len(parameters) * len(param_values_per_param.iloc[0]) * bar_width * 2 + 1

# 循环绘制多层分组条形
for seg_idx, seg_len in enumerate(segment_lengths):
    seg_data = melted_data[melted_data['Segment length'] == seg_len]
    for param_idx, param in enumerate(parameters):
        param_data = seg_data[seg_data['Parameter'] == param]
        param_values = param_values_per_param[param]
        for val_idx, val in enumerate(param_values):
            val_data = param_data[param_data['Parameter value'] == val]
            # 计算当前条形基准位置
            base_pos = seg_idx * segment_gap + param_idx * len(param_values) * bar_width * 2 + val_idx * bar_width * 2
            # 绘制Train score条形
            plt.bar(
                base_pos, 
                val_data[val_data['Score type'] == 'Train score']['Score'].values[0],
                width=bar_width, 
                label='Train score' if seg_idx == 0 and param_idx ==0 and val_idx ==0 else "",
                color='#1f77b4'
            )
            # 绘制Test score条形
            plt.bar(
                base_pos + bar_width, 
                val_data[val_data['Score type'] == 'Test score']['Score'].values[0],
                width=bar_width, 
                label='Test score' if seg_idx ==0 and param_idx ==0 and val_idx ==0 else "",
                color='#ff7f0e'
            )

# 设置x轴标签与刻度
x_ticks = []
x_labels = []
for seg_idx, seg_len in enumerate(segment_lengths):
    seg_base = seg_idx * segment_gap
    for param_idx, param in enumerate(parameters):
        param_base = seg_base + param_idx * len(param_values_per_param.iloc[0]) * bar_width * 2
        for val_idx, val in enumerate(param_values_per_param[param]):
            tick_pos = param_base + val_idx * bar_width * 2 + bar_width/2
            x_ticks.append(tick_pos)
            x_labels.append(f"{seg_len}\n{param}\n{val}")

plt.xticks(x_ticks, x_labels, rotation=45, ha='right')
plt.ylabel('Score')
plt.title('Multi-grouped Bar Plot: Segment Length → Parameter → Parameter Value')
plt.legend()
plt.tight_layout()
plt.show()

扩展适配

后续扩展到6个Segment length、每个Parameter下10个值时,只需调大画布尺寸(如figsize=(20,8)),代码逻辑无需修改即可自动适配分组数量。


R 实现(ggplot2)

思路

利用ggplot2的分组与分面功能,结合长格式数据,通过facet_wrap处理外层Segment length分组,用position_dodge实现Train/Test条形的并列展示。

完整代码

library(ggplot2)
library(tidyr)

# 构建目标数据框
data <- data.frame(
  `Segment length` = rep(c(16,32), each=9),
  Parameter = rep(c('n_estimators','max_depth','max_features'), each=3, times=2),
  `Parameter value` = c(5.0,10.0,15.0,2.0,6.0,10.0,0.1,0.3,0.5,
                        5.0,10.0,15.0,2.0,6.0,10.0,0.1,0.3,0.5),
  `Train score` = c(0.975414,0.982342,1.0,0.580884,1.0,1.0,1.0,1.0,1.0,
                    0.961905,0.988095,1.0,0.785714,1.0,1.0,1.0,1.0,1.0),
  `Test score` = c(0.807823,0.756803,0.801020,0.284014,0.824830,0.824830,0.845238,0.845238,0.845238,
                   0.714286,0.857143,0.857143,0.571429,0.857143,0.857143,0.904762,0.904762,0.857143)
)

# 转为长格式
melted_data <- pivot_longer(
  data, 
  cols = c(`Train score`, `Test score`),
  names_to = "Score type", 
  values_to = "Score"
)

# 绘制多层分组条形图
ggplot(melted_data, aes(x = interaction(Parameter, `Parameter value`), y = Score, fill = `Score type`)) +
  geom_bar(stat = "identity", position = position_dodge(width=0.8), width=0.7) +
  facet_wrap(~`Segment length`, scales = "free_x", nrow=1) +
  labs(x = "Parameter - Parameter Value", y = "Score", title = "Multi-grouped Bar Plot") +
  theme(
    axis.text.x = element_text(angle=45, hjust=1),
    plot.title = element_text(hjust=0.5),
    panel.spacing = unit(1, "cm")
  ) +
  scale_fill_manual(values = c("#1f77b4", "#ff7f0e"))

扩展适配

扩展分组数量时,ggplot2会自动调整分面布局;若需更紧凑的排版,可修改facet_wrap的nrow参数,或调整theme中的axis.text.x字体大小。


内容的提问来源于stack exchange,提问作者Oskar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 10:15:14