Python直方图:从核密度估计到高维空间解析

发布于:2025-03-21 ⋅ 阅读:(38) ⋅ 点赞:(0)

一、直方图的核心原理与数学本质

数据分布的视觉解码器

直方图(Histogram)是数据科学家的"分布显微镜",通过将连续数据划分为等宽区间(Bin),统计各区间的频数/频率,用相邻矩形条直观展示数据分布形态。其核心三要素:

  1. 区间划分:决定数据粒度的核心参数
  2. 统计方式:频数统计 vs 概率密度
  3. 归一化:数据标准化处理技巧

数学建模解析

直方图的矩形高度由以下公式决定:

h i = 频数 i 区间宽度 (概率密度模式) h_i = \frac{\text{频数}_i}{\text{区间宽度}} \quad \text{(概率密度模式)} hi=区间宽度频数i(概率密度模式)

当启用归一化(density=True)时,直方图总面积将归一化为1,此时可叠加理论概率密度曲线进行对比分析。

二、基础直方图绘制实战

快速入门模板

import numpy as np
import matplotlib.pyplot as plt

# 生成正态分布数据
data = np.random.normal(loc=0, scale=1, size=1000)

# 基础直方图
plt.figure(figsize=(10, 6))
hist = plt.hist(data, bins=15, 
                edgecolor='black', 
                alpha=0.7,
                color='#1f77b4')
plt.title('标准正态分布直方图')
plt.xlabel('数值区间')
plt.ylabel('频数')
plt.grid(axis='y', linestyle='--')
plt.show()

基础直方图示例

参数调优指南

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

# 生成数据
data = np.random.randn(1000)  # 生成标准正态分布数据

# 高级参数配置示例
plt.figure(figsize=(10, 6))
plt.hist(data, 
         bins=np.arange(-4, 4.5, 0.5),  # 自定义区间边界
         density=True,                 # 启用归一化
         histtype='stepfilled',        # 填充样式
         color='#ff7f0e',
         edgecolor='black',
         linewidth=1.2,
         alpha=0.6,
         label='归一化直方图')

# 叠加理论曲线
x = np.linspace(-4, 4, 200)
plt.plot(x, norm.pdf(x), 'r-', lw=2, label='理论PDF')

# 添加标题和标签
plt.title('归一化直方图与理论正态分布曲线')
plt.xlabel('数值')
plt.ylabel('概率密度')

# 添加图例和网格
plt.legend()
plt.grid(True, linestyle='--', alpha=0.7)

# 显示图形
plt.show()

代码说明:

  1. 数据生成

    • 使用np.random.randn(1000)生成1000个标准正态分布的随机数据点。
  2. 直方图参数配置

    • bins=np.arange(-4, 4.5, 0.5):自定义区间边界,从-4到4,步长为0.5。
    • density=True:启用归一化,使直方图的面积总和为1。
    • histtype='stepfilled':设置填充样式为阶梯填充。
    • color='#ff7f0e':设置填充颜色。
    • edgecolor='black':设置边框颜色。
    • linewidth=1.2:设置边框线宽。
    • alpha=0.6:设置透明度。
    • label='归一化直方图':设置图例标签。
  3. 理论曲线叠加

    • 使用scipy.stats.norm.pdf(x)计算理论正态分布的概率密度函数值。
    • 使用plt.plot绘制理论曲线,并设置颜色、线宽和标签。
  4. 图表美化

    • 添加标题、坐标轴标签。
    • 使用plt.legend()添加图例。
    • 使用plt.grid()添加网格线,设置网格样式和透明度。

运行这段代码将生成一个归一化的直方图,并叠加理论正态分布的概率密度函数曲线,帮助直观比较数据分布与理论分布的差异。
在这里插入图片描述

三、多维数据对比分析

分布对比

import numpy as np
import matplotlib.pyplot as plt

# 生成三种分布数据
normal_data = np.random.randn(1000)  # 正态分布
uniform_data = np.random.uniform(-3, 3, 1000)  # 均匀分布
gamma_data = np.random.gamma(2, 1, 1000)  # 伽马分布

# 并排对比
fig, ax = plt.subplots(1, 3, figsize=(18, 6))

# 统一配置参数
config = {'bins': 30, 'edgecolor': 'black', 'alpha': 0.7}

# 绘制直方图
ax[0].hist(normal_data, **config, color='blue', label='正态分布')
ax[1].hist(uniform_data, **config, color='green', label='均匀分布')
ax[2].hist(gamma_data, **config, color='red', label='伽马分布')

# 统一坐标轴范围
for axis in ax:
    axis.set_xlim(-5, 10)  # 调整X轴范围以适应伽马分布
    axis.set_ylim(0, 100)  # 统一Y轴范围
    axis.grid(True)  # 添加网格线
    axis.set_xlabel('数值')  # 添加X轴标签
    axis.set_ylabel('频数')  # 添加Y轴标签
    axis.legend()  # 添加图例

# 添加标题
ax[0].set_title('正态分布')
ax[1].set_title('均匀分布')
ax[2].set_title('伽马分布')

# 显示图形
plt.tight_layout()  # 自动调整子图间距
plt.show()

代码说明:

  1. 生成三种分布数据

    • normal_data:标准正态分布数据。
    • uniform_data:均匀分布数据,范围为[-3, 3]。
    • gamma_data:伽马分布数据,形状参数为2,尺度参数为1。
  2. 并排对比

    • 使用plt.subplots(1, 3)创建一个1行3列的子图布局。
    • 使用ax[i].hist分别绘制三种分布的直方图,并传递统一的配置参数config
  3. 统一坐标轴范围

    • 使用set_xlimset_ylim统一设置X轴和Y轴的范围,确保图表之间的对比性。
    • 添加网格线、坐标轴标签和图例。
  4. 添加标题

    • 为每个子图添加标题,分别标注对应的分布类型。
  5. 调整布局

    • 使用plt.tight_layout()自动调整子图间距,避免标签或标题重叠。

输出结果:
运行这段代码后,你将看到一个包含三个子图的图表,分别展示了正态分布、均匀分布和伽马分布的直方图。每个子图的样式和坐标轴范围一致,方便直观对比不同分布的特征。
在这里插入图片描述

累积分布分析

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

# 生成数据(例如标准正态分布数据)
data = np.random.randn(1000)

# 计算理论CDF曲线的x值范围
x = np.linspace(min(data), max(data), 1000)

# 绘制累积直方图(经验CDF)
plt.figure(figsize=(10, 6))
plt.hist(data, 
         bins=50,
         density=True,
         cumulative=True,  # 启用累积模式
         histtype='step',  # 使用阶梯样式
         linewidth=2,
         label='经验CDF')

# 绘制理论CDF曲线
plt.plot(x, norm.cdf(x), 'r--', linewidth=2, label='理论CDF')

# 添加标题和标签
plt.title('累积直方图与理论CDF曲线')
plt.xlabel('数值')
plt.ylabel('累积概率')

# 添加图例
plt.legend()

# 显示图形
plt.grid(True)
plt.show()

代码说明:

  1. 生成数据

    • 使用np.random.randn(1000)生成1000个标准正态分布的随机数据点。
  2. 绘制累积直方图

    • 使用plt.hist绘制直方图,并设置cumulative=True启用累积模式,从而绘制经验累积分布函数(CDF)。
    • 设置histtype='step'以阶梯样式显示直方图,便于与理论CDF曲线对比。
    • 设置linewidth=2增加线条宽度,使图形更清晰。
    • 添加label='经验CDF'为图例提供标签。
  3. 绘制理论CDF曲线

    • 使用scipy.stats.norm.cdf(x)计算理论CDF值。
    • 使用plt.plot绘制理论CDF曲线,设置颜色为红色、线型为虚线('r--'),并添加label='理论CDF'
  4. 图表美化

    • 添加标题、X轴和Y轴标签。
    • 使用plt.legend()添加图例。
    • 使用plt.grid(True)添加网格线,便于观察。

输出结果:
运行这段代码后,你将看到一个累积直方图(经验CDF)与理论正态分布的CDF曲线的对比图。经验CDF通过直方图的累积模式显示,而理论CDF曲线则以红色虚线叠加在图上,直观地展示了数据的经验分布与理论分布之间的差异。
在这里插入图片描述

四、进阶应用技巧

智能分箱算法

这段代码将展示不同分箱算法(autoscottfddoane)对直方图的影响,并为每种算法绘制一个子图。

import numpy as np
import matplotlib.pyplot as plt

# 生成数据(例如标准正态分布数据)
data = np.random.randn(1000)

# 定义不同的分箱算法
methods = ['auto', 'scott', 'fd', 'doane']

# 创建一个 2x2 的子图布局
plt.figure(figsize=(12, 8))
for i, method in enumerate(methods, 1):
    plt.subplot(2, 2, i)
    plt.hist(data, bins=method, 
             edgecolor='black',
             color=f'C{i}',  # 使用默认的颜色循环
             alpha=0.7)      # 设置透明度
    plt.title(f'{method} 分箱算法')
    plt.grid(True)           # 添加网格线

# 调整子图间距
plt.tight_layout()

# 显示图形
plt.show()

代码说明:

  1. 生成数据

    • 使用 np.random.randn(1000) 生成 1000 个标准正态分布的随机数据点。
  2. 分箱算法

    • 定义了四种分箱算法:autoscottfddoane
    • auto:Matplotlib 默认的分箱算法,会根据数据的分布自动选择合适的分箱数。
    • scott:基于数据的标准差和样本数量的分箱算法。
    • fd(Freedman-Diaconis):基于数据的四分位数间距(IQR)的分箱算法,对异常值不敏感。
    • doane:适用于正偏分布的分箱算法,适合小样本数据。
  3. 绘图逻辑

    • 使用 plt.figure 创建一个 12x8 的画布。
    • 使用 plt.subplot 创建 2x2 的子图布局。
    • 在每个子图中,使用 plt.hist 绘制直方图,并指定不同的分箱算法。
    • 设置 edgecolor='black' 为直方图的边框添加黑色边框。
    • 使用 color=f'C{i}' 为每个直方图指定不同的颜色。
    • 设置 alpha=0.7 为直方图添加透明度,便于观察重叠部分。
    • 使用 plt.title 添加每个子图的标题,显示所使用的分箱算法。
    • 使用 plt.grid(True) 为每个子图添加网格线。
  4. 调整布局

    • 使用 plt.tight_layout() 自动调整子图间距,避免标签或标题重叠。

输出结果:
运行这段代码后,你将看到一个 2x2 的子图布局,每个子图展示了不同分箱算法对直方图的影响。通过对比,可以直观地观察到不同分箱算法如何影响直方图的形状和细节。
在这里插入图片描述

二维直方图

import numpy as np
import matplotlib.pyplot as plt

# 生成二维相关数据
x = np.random.randn(10_000)
y = x * 0.5 + np.random.randn(10_000) * 0.2

# 绘制二维直方图
plt.figure(figsize=(10, 8))
hist = plt.hist2d(x, y, 
           bins=[np.linspace(-4, 4, 50), 
                 np.linspace(-3, 3, 50)],
           cmap='viridis',
           density=True)

# 添加颜色条
plt.colorbar(hist[3], label='概率密度')

# 添加标题和坐标轴标签
plt.title('二维直方图(热力图风格)')
plt.xlabel('X变量')
plt.ylabel('Y变量')

# 显示图形
plt.show()

代码说明:

  1. 生成数据

    • x 是标准正态分布数据。
    • y 是与 x 有一定线性相关性的数据,同时添加了一些随机噪声。
  2. 绘制二维直方图

    • 使用 plt.hist2d 绘制二维直方图。
    • bins 参数指定了 xy 方向的分箱边界,使用 np.linspace 生成等间距的分箱边界。
    • cmap='viridis' 设置颜色映射为 viridis,这是一个从浅黄到深蓝的渐变色。
    • density=True 将直方图归一化为概率密度。
  3. 添加颜色条

    • 使用 plt.colorbar 添加颜色条,并设置标签为“概率密度”。
  4. 添加标题和坐标轴标签

    • 使用 plt.title 添加标题。
    • 使用 plt.xlabelplt.ylabel 添加坐标轴标签。
  5. 显示图形

    • 使用 plt.show() 显示最终图形。

输出结果:
运行这段代码后,你将看到一个二维直方图,以热力图的形式展示了 xy 的联合分布。颜色条显示了不同颜色对应的概率密度值,帮助直观地理解数据的分布特征。
在这里插入图片描述

三维柱状图

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 生成二维正态分布数据
x = np.random.randn(10000)
y = x * 0.5 + np.random.randn(10000) * 0.5

# 设置bin宽度
bin_width = 0.3
bins_x = np.arange(-5, 5, bin_width)
bins_y = np.arange(-5, 5, bin_width)

# 计算二维直方图
hist, x_edges, y_edges = np.histogram2d(x, y, bins=[bins_x, bins_y], density=True)

# 准备三维柱状图的数据
x_pos, y_pos = np.meshgrid(x_edges[:-1], y_edges[:-1], indexing='ij')
x_pos = x_pos.flatten()
y_pos = y_pos.flatten()
z_pos = np.zeros_like(x_pos)  # 柱子的底部高度为0
dx = dy = bin_width * np.ones_like(z_pos)  # 柱子的宽度和深度
dz = hist.flatten()  # 柱子的高度(密度值)

# 绘制三维柱状图
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 根据密度值设置颜色
colors = plt.cm.hot(dz / np.max(dz))

# 绘制柱状图
ax.bar3d(x_pos, y_pos, z_pos, dx, dy, dz, color=colors, shade=True)

# 设置标签和标题
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Density')
ax.set_title('三维直方图(密度表示)')

# 添加颜色条
# 创建一个ScalarMappable对象
m = cm.ScalarMappable(cmap=plt.cm.hot)
m.set_array(dz)  # 设置数据范围

# 明确指定ax参数
cbar = plt.colorbar(m, ax=ax, label='Density')

plt.show()

三维直方图

五、性能优化建议

  1. 大数据优化:当数据量超过百万级时,改用numpy.histogram预计算
  2. 动态渲染:对交互式可视化,可使用Bokeh或Plotly的WebGL加速
  3. 分箱策略:优先选择'auto''fd'算法处理复杂分布

结语

掌握直方图的深度应用,等于拥有了数据分布的万能钥匙。通过灵活运用Python生态中的Matplotlib、NumPy、SciPy等工具,我们不仅能快速生成标准直方图,更能实现多维对比、累积分布分析等高级功能。建议读者在实践中尝试不同的分箱策略和可视化参数,找到最适合特定数据集的展示方式。


网站公告

今日签到

点亮在社区的每一天
去签到