Seaborn 概率直方图 - KDE 归一化

Seaborn probability histplot - KDE normalization

当使用默认统计数据(密度)和 KDE 标志设置为 True 绘制 histplot 时,曲线下的面积等于 1。来自 Seaborn 文档:

"密度轴上的单位是一个常见的混淆来源。虽然核密度估计产生概率分布,但每个点的曲线高度给出的是密度,而不是概率。只能获得概率通过在一个范围内对密度进行积分。曲线被归一化,因此所有可能值的积分为 1,这意味着密度轴的比例取决于数据值。"

下面是密度 histplot 的示例,默认 KDE 归一化为 1。

但是,您也可以绘制直方图,统计数据为 countprobability。在这些之上绘制 KDE 将产生以下结果:

KDE 是如何规范化的?该面积当然不等于 1,但必须以某种方式归一化。我在文档中找不到这个,唯一的解释是关于为密度直方图绘制的 KDE。在此感谢任何帮助,谢谢!

据我了解,KDE(内核密度估计)只是对数据点形成的曲线进行平滑处理。三种表示之间的变化是计算它的值:

  • 通过密度估计,KDE曲线下的总面积为1;这意味着您可以估计通过积分计算找到两个边界值之间的值的概率。我认为他们用曲线平滑数据点,计算曲线下的面积并将所有值除以面积,以便曲线保持相同的外观但面积变为 1.

  • 通过概率估计,KDE曲线下的总面积并不重要:每个类别都有一定的概率(例如P(x in [115; 125])= 0.2)和总和每个类别的概率等于 1。因此,他们不会计算 KDE 曲线下的面积,而是计算所有样本并将每个 bin 的计数除以总数。

  • 通过计数估计,您会得到一个标准的 bin/count 分布,而 KDE 只是平滑数字,以便您可以估计值的分布 - 这样您就可以估计您的如果您采取更多措施或使用更多垃圾箱,观察结果可能看起来像。

所以总而言之,KDE 曲线保持不变:它是样本数据分布的平滑。但是有一个因素会根据您感兴趣的数据表示形式应用于样本值。

但是,请对我所写的内容持保留态度:从数学的角度来看,我认为我离事实不远,但也许有人可以用更精确的术语来解释它 - 或者纠正我,如果我错了

这里有一些关于 Kerneld 密度估计的读物:https://en.wikipedia.org/wiki/Kernel_density_estimation;但简而言之,这是一种平滑方法,具有一些特殊的数学属性,具体取决于所使用的参数。

嗯,kde的面积是1,要画出符合直方图的kde,kde需要乘以直方图的面积。

对于密度图,直方图的面积为1,因此可以按原样使用kde。

对于计数图,直方图高度的总和将是给定数据的长度(每个数据项将恰好属于一个条)。直方图的面积将是总高度乘以 bin 的宽度。 (当 bin 的宽度不相等时,调整 kde 将非常棘手)。

对于概率图,直方图高度的总和将为 1(对于 100 %)。总面积将是 bin_width 乘以高度,因此等于 bin_width.

这里有一些代码可以解释发生了什么。它使用标准的 matplotlib 条,numpy 来计算直方图,scipy 用于 kde:

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

data = [115, 127, 128, 145, 160]
bin_values, bin_edges = np.histogram(data, bins=4)
bin_width = bin_edges[1] - bin_edges[0]
total_area = bin_width * len(data)

kde = gaussian_kde(data)
x = np.linspace(bin_edges[0], bin_edges[-1], 200)

fig, axs = plt.subplots(ncols=3, figsize=(14, 3))
kws = {'align': 'edge', 'color': 'dodgerblue', 'alpha': 0.4, 'edgecolor': 'white'}
axs[0].bar(x=bin_edges[:-1], height=bin_values / total_area, width=bin_width, **kws)
axs[0].plot(x, kde(x), color='dodgerblue')
axs[0].set_ylabel('density')

axs[1].bar(x=bin_edges[:-1], height=bin_values / len(data), width=bin_width, **kws)
axs[1].plot(x, kde(x) * bin_width, color='dodgerblue')
axs[1].set_ylabel('probability')

axs[2].bar(x=bin_edges[:-1], height=bin_values, width=bin_width, **kws)
axs[2].plot(x, kde(x) * total_area, color='dodgerblue')
axs[2].set_ylabel('count')

plt.tight_layout()
plt.show()