直方图用于展示连续数据的分布情况,将数据划分为若干个区间(bins),并用条形表示每个区间内数据的频数或频率。
Matplotlib 的 plt.hist() 函数提供了灵活的参数,可以轻松绘制直方图,并支持多组数据比较、密度曲线等高级功能。
最简单的直方图只需传入一维数据数组:
import matplotlib.pyplot as plt
import numpy as np
# 生成正态分布随机数据
data = np.random.randn(1000) # 1000个标准正态分布数据
plt.hist(data)
plt.title('基础直方图')
plt.xlabel('数值')
plt.ylabel('频数')
plt.show()
bins 参数可以指定区间数量或具体的区间边界:
data = np.random.randn(1000)
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.hist(data, bins=5)
plt.title('bins=5')
plt.subplot(1, 3, 2)
plt.hist(data, bins=20)
plt.title('bins=20')
plt.subplot(1, 3, 3)
plt.hist(data, bins=np.arange(-4, 4.5, 0.5)) # 自定义区间边界
plt.title('自定义bins')
plt.tight_layout()
plt.show()
bins 可以是整数(区间个数),也可以是序列(区间边界)。hist() 支持多种样式参数:
| 参数 | 说明 | 示例 |
|---|---|---|
color | 柱体颜色 | color='steelblue' |
edgecolor | 边框颜色 | edgecolor='black' |
linewidth | 边框线宽 | linewidth=1.2 |
alpha | 透明度 | alpha=0.7 |
histtype | 直方图类型:'bar'(默认,条形)、'step'(轮廓)、'stepfilled'(填充轮廓) | histtype='step' |
data = np.random.randn(1000)
plt.hist(data, bins=30, color='lightcoral', edgecolor='darkred', linewidth=1.5, alpha=0.8)
plt.title('定制样式的直方图')
plt.show()
使用透明度叠加,或调整 histtype 为 step 绘制轮廓:
data1 = np.random.randn(1000)
data2 = np.random.randn(1000) + 1 # 偏移1个单位
plt.hist(data1, bins=30, alpha=0.5, label='数据集1')
plt.hist(data2, bins=30, alpha=0.5, label='数据集2')
plt.legend()
plt.title('两组直方图叠加')
plt.show()
plt.hist(data1, bins=30, histtype='step', linewidth=2, label='数据集1')
plt.hist(data2, bins=30, histtype='step', linewidth=2, label='数据集2')
plt.legend()
plt.title('轮廓直方图')
plt.show()
通过 stacked=True 将多组数据堆叠显示:
data1 = np.random.randn(1000)
data2 = np.random.randn(1000) + 2
data3 = np.random.randn(1000) - 1
plt.hist([data1, data2, data3], bins=30, stacked=True,
label=['组1', '组2', '组3'], alpha=0.7)
plt.legend()
plt.title('堆叠直方图')
plt.show()
stacked=True 实现堆叠。density=True 将纵坐标转换为概率密度,使总面积为1;cumulative=True 绘制累积直方图:
data = np.random.randn(1000)
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.hist(data, bins=30, density=True)
plt.title('概率密度直方图')
plt.ylabel('密度')
plt.subplot(1, 3, 2)
plt.hist(data, bins=30, cumulative=True)
plt.title('累积直方图')
plt.ylabel('累积频数')
plt.subplot(1, 3, 3)
plt.hist(data, bins=30, density=True, cumulative=True)
plt.title('累积概率密度')
plt.ylabel('累积概率')
plt.tight_layout()
plt.show()
通常与 SciPy 或 seaborn 结合,这里演示使用 scipy 计算密度:
from scipy import stats
data = np.random.randn(1000)
# 绘制直方图(概率密度形式)
plt.hist(data, bins=30, density=True, alpha=0.6, color='steelblue', edgecolor='black')
# 拟合核密度估计
kde = stats.gaussian_kde(data)
x = np.linspace(data.min(), data.max(), 200)
plt.plot(x, kde(x), 'r-', linewidth=2, label='核密度估计')
plt.title('直方图 + 密度曲线')
plt.legend()
plt.show()
density=True 使直方图与密度曲线量纲一致。使用 plt.hist2d() 展示两个变量的联合分布:
x = np.random.randn(5000)
y = np.random.randn(5000) * 0.5 + x
plt.hist2d(x, y, bins=40, cmap='Blues')
plt.colorbar(label='频数')
plt.title('二维直方图')
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
cmap 指定颜色映射,colorbar 显示颜色条。hist() 返回三个对象:n (频数/密度), bins (区间边界), patches (条形对象列表),可用于进一步定制:
data = np.random.randn(1000)
n, bins, patches = plt.hist(data, bins=20, color='skyblue', edgecolor='black')
# 找到频数最高的条形并改变颜色
max_idx = np.argmax(n)
patches[max_idx].set_facecolor('red')
plt.title('高亮频数最高的条形')
plt.show()
patches 可以单独修改每个条形的属性。# 生成三组数据:正态分布、偏态分布、双峰分布
np.random.seed(42)
data1 = np.random.randn(1000)
data2 = np.random.exponential(1, 1000) * 2
data3 = np.concatenate([np.random.randn(500) - 2, np.random.randn(500) + 2])
plt.figure(figsize=(10, 6))
plt.hist(data1, bins=30, alpha=0.5, density=True, label='正态分布')
plt.hist(data2, bins=30, alpha=0.5, density=True, label='指数分布')
plt.hist(data3, bins=30, alpha=0.5, density=True, label='双峰分布')
plt.title('不同分布对比直方图 (概率密度)')
plt.xlabel('数值')
plt.ylabel('密度')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
使用 savefig() 保存为图片:
plt.savefig('histogram.png', dpi=300, bbox_inches='tight') # PNG
plt.savefig('histogram.pdf', bbox_inches='tight') # 矢量PDF
直方图是探索数据分布的基础工具,通过调整bins、叠加密度曲线、使用二维直方图,可以深入洞察数据特征。下一章我们将学习箱线图的绘制,用于展示数据的分散情况。