什么是直方图与密度图?科研中正确理解数据分布的实用指南

详细介绍直方图和密度图的原理、适用场景、常见陷阱,以及Python/R可直接运行的绘图代码,帮助科研人员在探索性数据分析中少走弯路。

更新于2026年8月3日

什么是直方图与密度图?科研中正确理解数据分布的实用指南

在科研工作中,拿到一组新数据后,很多人第一反应是算均值、标准差、跑个t检验或回归。但真正靠谱的分析,往往从“看分布”开始。分布决定了你该用什么统计方法、是否需要变换数据、异常值有多严重,甚至直接影响结论的可信度。

直方图和密度图是最常用的两种工具。它们看起来简单,用好了能省下很多弯路;用不好,反而容易误导自己。下面我们把这两种图说清楚,并给出可直接上手的画法。

什么是直方图(Histogram)与密度图(Density Plot)?

直方图是把连续数值变量划分成若干等宽的区间(称为“箱”或“bin”),然后用柱子的高度表示每个区间里数据点的数量(或频率、密度)。它本质上是频率表的可视化版本。

举一个经典例子:

直方图示例图

这是一张表示泰坦尼克号乘客年龄的直方图(来源:Claus Wilke《Fundamentals of Data Visualization》)。不同年龄段的人数一目了然。

还有这张Matplotlib上的图(来源:https://matplotlib.org/stable/gallery/statistics/hist.html):

直方图示例图

直方图有一个关键参数——箱宽(bin width)。箱太窄,图会显得嘈杂、毛刺多;箱太宽,细节(比如双峰、小凹陷)会被抹平。上面我们引用的Wilke的书里用同一组数据画了四种不同箱宽的对比,非常直观地说明了这个问题。

密度图(更准确地说是核密度估计图,Kernel Density Estimate, KDE)则是对直方图的平滑版本。它不把数据硬分成箱子,而是在每个数据点上放置一个“核函数”(最常用的是高斯核,也就是小钟形曲线),再把所有核叠加起来,得到一条连续的曲线。曲线下的总面积通常归一化为1,因此纵轴表示的是概率密度。

同样以泰坦尼克年龄为例,密度图能更平滑地展示整体形状:

密度图示意图

Seaborn上的例子也很典型(来源:https://seaborn.pydata.org/generated/seaborn.kdeplot.html):

密度图示意图

密度图的关键参数是带宽(bandwidth)。带宽太小,曲线会跟着噪声起伏;带宽太大,真实结构会被过度平滑。另外,密度估计在数据稀疏的两端容易“泄漏”——比如年龄出现负数,这显然不合理,画图时需要注意截断。

简单对比:

  • 直方图:离散、直接反映计数,对箱宽敏感。
  • 密度图:连续、更接近底层概率分布,对带宽敏感,但通常更适合多组比较。

两者没有绝对优劣,很多时候可以叠在一起画(直方图+密度曲线),互相验证。

直方图适用场景

直方图特别适合以下情况:

1. 初步探索单变量分布

样本量中等或偏大(通常几百以上)时,快速看看数据是单峰还是多峰、是否偏斜、有没有明显断点。比如基因表达量、反应时间、测量误差等。

2. 需要明确看到“数量”时

如果你关心的是“这个区间大概有多少个样本”,而不是相对密度,直方图更直观。论文里想强调“大多数样本集中在某范围”,直方图很有说服力。

3. 数据本身有自然区间或离散感

例如年龄(按岁)、考试分数(按十分制)、某些传感器读数。箱宽可以对应实际意义。

4. 样本量较小或想保留原始信息时

密度估计在小样本下容易不稳定,直方图相对更“老实”。

需要注意的坑:

  • 箱宽选择没有唯一正确答案。建议多试几种(或用Freedman-Diaconis、Scott等规则作为起点),并在正文或补充材料里说明你最终选的理由。
  • 不同组之间如果直接叠直方图,容易看不清。此时更推荐后面说的密度图或分面图。

密度图适用场景

密度图在以下场景通常更占优势:

1. 比较多个分布

想同时看3–4个组的分布差异时,重叠的半透明密度曲线比堆叠/重叠直方图清晰得多。还是上面我提到Wilke书中用四种牛品种的乳脂率密度图就是很好的例子。

2. 关注分布的整体形状与细微结构

识别双峰、偏度、尾部厚度、潜在的亚群时,平滑曲线往往比柱状图更敏感。

3. 样本量较大时

数据点足够多,核密度估计会比较稳定,带宽选择的影响也相对可控。

4. 需要与理论分布对比

想把经验分布和正态、伽马等理论曲线叠在一起看拟合好坏,密度图是自然选择。

不适用或需谨慎的情况:

  • 样本量很小(比如几十个点),容易过拟合噪声。
  • 数据有明确边界(年龄不能为负、比例不能超过1),要记得设置截断或边界校正。
  • 需要报告精确计数时,密度图的纵轴不如直方图直观。

实践中,很多人会同时画直方图+密度曲线,或者用`stat="density"`把直方图本身也归一化,方便直接比较。

如何画直方图和密度图?

在科研场景下,大多数人使用Python和R语言工具,我们在这里给出一些简洁可运行示例。代码尽量保持干净,方便大家直接复制修改。

ython(matplotlib + seaborn)

```python

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns

# 示例数据

np.random.seed(42)

data = np.random.normal(loc=50, scale=15, size=800)

data2 = np.random.normal(loc=65, scale=12, size=600)

# 1. 基础直方图

plt.figure(figsize=(8, 5))

plt.hist(data, bins=30, color='steelblue', edgecolor='white', alpha=0.8)

plt.xlabel('Value')

plt.ylabel('Count')

plt.title('Basic Histogram')

plt.show()

# 2. 直方图 + 密度曲线(推荐)

plt.figure(figsize=(8, 5))

sns.histplot(data, bins=30, kde=True, color='steelblue', edgecolor='white',

line_kws={'linewidth': 2})

plt.xlabel('Value')

plt.ylabel('Count / Density')

plt.title('Histogram with Density Curve')

plt.show()

# 3. 多组密度图对比

plt.figure(figsize=(8, 5))

sns.kdeplot(data, label='Group A', fill=True, alpha=0.4, linewidth=2)

sns.kdeplot(data2, label='Group B', fill=True, alpha=0.4, linewidth=2)

plt.xlabel('Value')

plt.ylabel('Density')

plt.legend()

plt.title('Overlapping Density Plots')

plt.show()

# 4. 调整带宽(bw_adjust)

sns.kdeplot(data, bw_adjust=0.5) # 更敏感

sns.kdeplot(data, bw_adjust=1.5) # 更平滑

常用参数提示:

  • `bins`:可直接给整数,或用`np.histogram_bin_edges`自己算。
  • `stat="density"`或`stat="probability"`:把纵轴改成密度或概率。
  • `common_norm=False`:多组比较时让每组自己归一化。

R(ggplot2)

R

library(ggplot2)

library(dplyr)

# 示例数据

set.seed(42)

df <- data.frame(

value = c(rnorm(800, 50, 15), rnorm(600, 65, 12)),

group = rep(c("A", "B"), times = c(800, 600))

)

# 直方图 + 密度

ggplot(df, aes(x = value)) +

geom_histogram(aes(y = after_stat(density)), bins = 30,

fill = "steelblue", color = "white", alpha = 0.7) +

geom_density(color = "darkred", linewidth = 1) +

theme_minimal() +

labs(title = "Histogram with Density", x = "Value", y = "Density")

# 多组密度

ggplot(df, aes(x = value, fill = group, color = group)) +

geom_density(alpha = 0.4, linewidth = 1) +

theme_minimal() +

labs(title = "Density by Group")

在R里也可以用`geom_histogram(bins = ...)`单独画直方图,或`geom_density(bw = ...)`控制带宽。

建议

1. 总是检查不同参数:至少试2–3种箱宽/带宽,把最终选择写进方法或补充材料。

2. 报告时写清楚:箱宽怎么定的、是否用了密度归一化、带宽选择依据。

3. 小样本优先直方图:大样本可以更放心地用密度图。

4. 多组比较时优先密度或分面直方图:避免堆叠直方图带来的视觉误导。

5. 边界问题:年龄、比例等有物理限制的变量,记得检查密度曲线是否越界。

直方图和密度图本身不复杂,真正拉开差距的是“是否认真对待参数选择”和“是否在正确的场景使用正确的图”。把这两步做好,后面的统计检验和建模会稳很多。

如果你正在写论文,建议把最终选定的图连同参数说明一起放进补充材料——审稿人看到你认真探索过分布,通常会更放心。

撰稿人
标签
学术科研
目录
订阅邮件
订阅我们的邮箱后可提前获得AJE作者资源的文章,享受AJE服务的折扣,以及更多的优惠

查看 "隐私协议"

AJE图表处理服务:加速文稿发表

无论您是有需要符合期刊指南的现有图形文件,还是想创建全新的插图、图形摘要或短动画,我们的团队都能提供帮助。