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

如何归一化由2D直方图生成的热力图?

当然可以搞定这个问题!你想让热力图反映分布而非样本量带来的频率差异,核心就是把绝对计数转换成相对密度或者做统一的归一化处理。下面给你几种实用的方法,一步步来:

方法1:直接用内置的密度归一化(最省心)

如果你用的是Matplotlib的hist2d函数,它自带了density=True参数——这个参数会自动把每个bin的绝对计数转换成概率密度,也就是计数除以(总样本数×每个bin的面积)。这样一来,不管两组数据的样本量差多少,热力图的颜色都只反映数据的分布密度,完全消除了样本量的影响。

举个实现代码的例子:

import matplotlib.pyplot as plt
import numpy as np

# 生成模拟数据(模拟你的x1-y1和x2-y2样本量差异)
np.random.seed(42)
x1, y1 = np.random.multivariate_normal([0,0], [[1,0.5],[0.5,1]], 10000).T
x2, y2 = np.random.multivariate_normal([0,0], [[1,0.5],[0.5,1]], 1000).T

# 绘制归一化后的热力图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

# 第一组数据(10k样本)
hist1, xedges, yedges, im1 = ax1.hist2d(x1, y1, bins=30, density=True, cmap='viridis')
ax1.set_title('x1-y1 (10k samples, density normalized)')
plt.colorbar(im1, ax=ax1, label='Probability Density')

# 第二组数据(1k样本)
hist2, _, _, im2 = ax2.hist2d(x2, y2, bins=30, density=True, cmap='viridis')
ax2.set_title('x2-y2 (1k samples, density normalized)')
plt.colorbar(im2, ax=ax2, label='Probability Density')

plt.tight_layout()
plt.show()

这样生成的两张图,颜色刻度完全对应相同的密度水平,你能直接对比两组数据的分布模式,不会被样本量干扰。

方法2:统一全局归一化到0-1范围(跨图对比更直观)

如果你希望所有热力图都用同一个0-1的颜色刻度(0代表最低密度,1代表所有数据集中的最大密度),可以先计算所有数据集的最大密度值,再统一设置vmin和vmax:

# 先提前计算所有数据的密度值
hist1, _, _ = np.histogram2d(x1, y1, bins=30, density=True)
hist2, _, _ = np.histogram2d(x2, y2, bins=30, density=True)

# 找出所有数据中的最大密度,作为全局参考
global_max_density = max(hist1.max(), hist2.max())

# 绘图时统一使用这个全局最大值作为vmax
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

im1 = ax1.hist2d(x1, y1, bins=30, density=True, cmap='viridis', vmin=0, vmax=global_max_density)
ax1.set_title('x1-y1 (normalized to global max density)')
plt.colorbar(im1[3], ax=ax1, label='Normalized Density (0-1)')

im2 = ax2.hist2d(x2, y2, bins=30, density=True, cmap='viridis', vmin=0, vmax=global_max_density)
ax2.set_title('x2-y2 (normalized to global max density)')
plt.colorbar(im2[3], ax=ax2, label='Normalized Density (0-1)')

plt.tight_layout()
plt.show()

这种方法的好处是,所有图的颜色标尺完全一致,能一眼看出哪组数据的某些区域密度相对更高。

方法3:单图内部归一化(聚焦自身分布)

如果你的需求是让每个热力图自己的最大密度对应1,最小对应0(只看单组数据内部的相对分布),可以手动计算每个bin的计数,然后除以该组数据的最大计数:

# 先计算每组数据的绝对计数直方图
counts1, xedges, yedges = np.histogram2d(x1, y1, bins=30)
counts2, _, _ = np.histogram2d(x2, y2, bins=30)

# 内部归一化到0-1范围
norm_counts1 = counts1 / counts1.max()
norm_counts2 = counts2 / counts2.max()

# 用pcolormesh绘制归一化后的矩阵
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

im1 = ax1.pcolormesh(xedges, yedges, norm_counts1.T, cmap='viridis', vmin=0, vmax=1)
ax1.set_title('x1-y1 (self-normalized to 0-1)')
plt.colorbar(im1, ax=ax1, label='Relative Frequency')

im2 = ax2.pcolormesh(xedges, yedges, norm_counts2.T, cmap='viridis', vmin=0, vmax=1)
ax2.set_title('x2-y2 (self-normalized to 0-1)')
plt.colorbar(im2, ax=ax2, label='Relative Frequency')

plt.tight_layout()
plt.show()

这种方式适合单独分析每组数据的内部分布强度,但跨图对比时要注意,因为各自的“1”代表的绝对计数不一样。


总结一下:

  • 优先用density=True,它是最直接消除样本量影响的方式,让热力图反映真实分布密度;
  • 要跨图统一对比,就用全局最大密度作为参考设置vmin/vmax;
  • 只看单组内部相对分布,就手动做内部归一化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:50:33