均值 ± 标准误柱状图(分组)
GAL-0005
用柱高表示各组均值,用误差线表示均值的标准误(SE),按两个分组因素并排排列。常见于论文,用来比较各组均值的大小及其估计精度。
图与代码

code/R/main.R
suppressPackageStartupMessages({
library(ggplot2)
library(dplyr)
})
d <- read.csv("data/toothgrowth.csv", encoding = "UTF-8")
d$dose <- factor(d$dose, levels = c(0.5, 1, 2))
d$supp <- factor(d$supp, levels = c("OJ", "VC"))
# 均值与标准误(SE = SD / sqrt(n))由代码从原始数据计算
s <- d %>%
group_by(dose, supp) %>%
summarise(mean = mean(len), se = sd(len) / sqrt(n()), .groups = "drop")
p <- ggplot(s, aes(x = dose, y = mean, fill = supp)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7, colour = "grey20", linewidth = 0.4) +
geom_errorbar(aes(ymin = mean - se, ymax = mean + se), position = position_dodge(width = 0.8),
width = 0.25, linewidth = 0.5, colour = "grey20") +
scale_fill_manual(values = c(OJ = "#66C2A5", VC = "#FC8D62"),
labels = c("Orange juice", "Ascorbic acid")) +
scale_y_continuous(expand = expansion(mult = c(0, 0.08))) +
labs(x = "Dose (mg/day)", y = "Tooth length (mean ± SE)", fill = "Supplement") +
theme_classic(base_size = 12) +
theme(legend.position = "top")
ggsave("outputs/figure_r.png", p, width = 6, height = 4.5, dpi = 300, bg = "white")
code/py/main.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scienceplots # noqa: F401
from matplotlib.patches import Patch
plt.style.use(["science", "no-latex"])
plt.rcParams.update({"font.family": "sans-serif", "font.size": 11}) # 与 R 版(theme_classic 无衬线)统一
d = pd.read_csv("data/toothgrowth.csv")
doses = [0.5, 1.0, 2.0]
supps = ["OJ", "VC"]
labels = {"OJ": "Orange juice", "VC": "Ascorbic acid"}
colors = {"OJ": "#66C2A5", "VC": "#FC8D62"}
dodge, width = 0.8, 0.7
fig, ax = plt.subplots(figsize=(6, 4.5))
for i, dose in enumerate(doses):
for j, s in enumerate(supps):
y = d.loc[(d["dose"] == dose) & (d["supp"] == s), "len"].to_numpy()
m = y.mean()
se = y.std(ddof=1) / np.sqrt(len(y)) # SE = SD / sqrt(n),由代码从原始数据计算
x0 = i + (j - 0.5) * dodge / 2
ax.bar(x0, m, width=width / 2, color=colors[s], edgecolor="#333333", linewidth=0.6)
ax.errorbar(x0, m, yerr=se, color="#333333", lw=0.8, capsize=3, capthick=0.8)
ax.set_xticks(range(3))
ax.set_xticklabels(["0.5", "1", "2"])
ax.set_xlabel("Dose (mg/day)")
ax.set_ylabel("Tooth length (mean ± SE)")
ax.margins(y=0.08)
ax.set_ylim(bottom=0)
ax.legend(handles=[Patch(facecolor=colors[s], edgecolor="#333333", label=labels[s]) for s in supps],
title="Supplement", loc="upper left", ncol=2, frameon=False)
ax.tick_params(axis="x", which="minor", bottom=False, top=False) # 分类横轴不要次刻度
fig.savefig("outputs/figure_py.png", dpi=300, facecolor="white")什么时候用
- 比较多个组的均值,并同时表达均值估计的不确定性
- 论文或报告中对均值差异做简洁概括
- 两个分组因素(如剂量 × 处理方式)的并列比较
常见误用
- 柱状图只呈现均值与误差线,会掩盖数据的实际分布、离群点和样本量;样本量不大时建议叠加原始数据点或改用箱线图
- 标准误(SE)描述均值估计的精度,标准差(SD)描述个体数据的离散,二者不能混用;图注必须写明误差线是 SE 还是 SD
- 误差线不重叠不等于差异显著,重叠也不等于不显著;差异需用相应的统计检验判断
- 柱状图纵轴应从 0 开始,截断纵轴会夸大组间差异
数据与下载
数据:R 内置数据集 ToothGrowth(datasets 包)(R 内置数据集(随 R 分发,GPL-2 | GPL-3))。60 只豚鼠的成牙本质细胞长度(len,R 文档:负责牙齿生长的成牙本质细胞的长度),分为 3 个维生素 C 剂量(0.5、1、2 mg/天)和 2 种给药方式(橙汁 OJ、抗坏血酸 VC),每个组合 10 只。均值与标准误(SD/√n)由代码从原始数据计算。
下载包 sha256:0f7e2b5aa1612ed0ef6eedd626ae05eabc171ef8d21a260a47410665bf219dd7