尝试可视化一个分布时,是否遇到过这样的问题:每次调整直方图的分箱大小,图形的形状就变了?
通常是这样的。您选 10 个箱,看起来像一条平滑的曲线;换成 30 个箱,就出现了多个峰。数据没变,但不同的分箱数会给出不同的解读。这是直方图最大的毛病:它并不展示“分布”本身,而是展示某一种版本;而这种版本受到您随机设定的参数影响。
KDE(核密度估计)采用了不同的方法。它不把数据切分进箱,而是在每个数据点上放置一条小而平滑的曲线,然后把它们加总。这会给出一个对背后分布的单一、连续的估计。
本文将带您建立 KDE 的直觉、走读其公式、解释带宽如何控制平滑度,并提供 Python 和 R 的实用示例。
还不熟悉直方图?这里有一份全面指南: 频率直方图 ,助您快速上手。
什么是核密度估计?
核密度估计是一种非参数方法,用于估计数据集的概率密度函数。
“非参数”正是它的不同之处。
参数方法需要假设数据服从某个特定分布——如正态、指数——然后拟合参数去匹配。如果假设错了,模型就错了。KDE 不做这样的假设。它让数据自己“发声”,直接从观测构建对底层分布的估计。
输出是一条平滑曲线,展示数值可能落在哪里——以及有多大可能。曲线的高点意味着密集区域,低点意味着稀疏区域。
为什么要用核密度估计?
直方图是可视化分布的默认工具,但它有个问题:您看到的形状取决于您选择的分箱数量。而这个分箱参数是由您来定。两个人看同一数据集,仅仅因为分箱数不同,就可能得出完全不同的结论。
使用 KDE,不再强行把数据塞进箱里,而是生成一条平滑、连续的曲线,不会因为您事先设定的任意参数而改变。
因此它在以下方面很有用:
在不受分箱大小偏差影响的情况下可视化分布的整体形状
检测多峰、偏态或厚尾等模式
在同一图上比较不同组的分布
在建模前更清晰地了解数据情况
KDE 的直观理解
对每个数据点放置一条小而平滑的曲线,这条曲线称为 核(kernel) 。然后,把这些单独的曲线全部相加。
最终得到一条展示数据密度的平滑曲线。数据点聚集的地方,多条核会重叠并叠加,曲线就会上升;数据稀疏的地方,核几乎不重叠,曲线就保持较低。每个点对最终估计的贡献都是相同的。
想象您记录了一门课学生的期末成绩。与其用直方图分箱,KDE 会在每个分数上放一条小而平滑的曲线。分数聚集的地方——比如 70–75 分附近——曲线会叠加上升;而一个考了 95 分的学生,只会在尾部加出一个小凸起。
下图正是这种效果。大多数学生集中在平均分附近,且有一位学生分数高得多:
KDE 可视化
核密度估计公式
KDE 的公式看起来比实际难。
KDE 公式
各部分含义如下:
n 是数据点的数量
x_i 是数据集中各个具体的数据点
K 是核函数——放在每个点上的平滑曲线
h 是带宽——控制每个核的宽度
x 是您要评估密度的位置
通俗地说,该公式表示:对于任意一点 x,看每个数据点 x_i 离它有多近,用核函数 K 对这种“接近程度”加权,并在全部 n 个点上取平均。对范围内的每个 x 都这么做,就得到完整的密度曲线。
带宽 h 位于 K 内部分数的分母。较小的 h 使核更窄,因此只有非常近的点会影响估计;较大的 h 会扩大影响范围。稍后将详细介绍。
什么是核函数?
核就是您放在每个数据点上的平滑曲线。它定义了该点的影响如何向邻近点扩散。
每个核都以某个数据点为中心,并根据距离分配权重。越靠近中心的点权重越高,越远的点权重越低,甚至为零。具体的加权形状取决于您选择的核。
常见的三种选择:
高斯: 钟形曲线。为数据集中的每个点分配权重,且影响随距离衰减。这是大多数库的默认选项,实践中表现良好
均匀: 平顶矩形。固定距离内的点权重相同,外部的权重为零。简单,但平滑度较差
Epanechnikov: 抛物线形,在均方误差意义上是数学上最优的。比高斯更高效,但在可视化效果上很少带来明显差异。
多数情况下,核的选择影响不大。对同一数据、用相同带宽,两个不同的核通常会产生几乎相同的曲线。真正更重要的是带宽——我们接下来就看它。
带宽在 KDE 中的作用
带宽是对 KDE 输出影响最大的单一参数,甚至超过核的选择。
它控制每个核的宽度。窄核只吸收附近点的影响,宽核则把影响扩散到更大的范围。结果要么是紧贴数据的曲线,要么是更平滑的曲线。
小带宽
小带宽会让每个核紧而窄。估计会对每个数据点产生剧烈反应,这意味着既能捕捉到数据的真实结构,也会拾取噪声。
在实践中,这看起来像是一条多处尖峰的曲线。其中一些峰反映了真实聚类,另一些只是平滑不足造成的伪影。难点在于很难区分二者。
小带宽的 KDE
大带宽
大带宽会让每个核更宽。相邻核大量重叠,最终曲线会更平滑。
如果过于平滑,就会失去真实结构。两个明显的聚类可能被抹成一条曲线;厚尾分布可能看起来对称。可视化反而可能在“藏”信息。
大带宽的 KDE
如何找到合适的带宽
没有普适正确的带宽。目标是在足以滤掉噪声的同时,不至于把真实模式抹平。
大多数库提供自动带宽选择方法,其中 Silverman 经验法则 最常见。它根据样本量和数据的标准差选择带宽。对近似正态分布效果好,但可能对多峰分布过度平滑。
如果拿不准,可以尝试几个带宽值并比较曲线。差异会告诉您很多关于数据的信息。
KDE 与直方图
直方图和 KDE 都能展示数据的分布——但方式截然不同。
直方图
直方图把数据划分到离散的箱中,并统计每个箱中点的数量。它快速、直观,易于向非技术受众解释。
问题在于对分箱的敏感性。只要改变箱数,形状就变了。没有客观正确的分箱数量,这意味着两个人看同一数据,仅因这个选择不同就会得出不同结论。
直方图还会产生台阶状、不连续的形状。用于快速查看还好,但可能遮蔽真实的底层分布。
KDE
KDE 给出的是没有分箱参与的平滑、连续曲线。它更擅长揭示分布的真实形状——诸如偏态、多峰或厚尾等,而直方图可能因为分箱选择而忽略或误导。
代价是 KDE 引入了自己的参数——带宽——并且计算量更大。它也不太直观,因为 y 轴显示的是概率密度而不是计数,这可能会让不熟悉该概念的读者困惑。
各自何时使用
当您需要对数据进行快速、易解释的总结,或受众不熟悉密度估计时,用直方图;当分布形状很重要——比如要比较不同组,或要检测数据中的多峰——则使用 KDE。
直方图与 KDE 对比
实践中,它们常常结合使用:直方图显示计数,叠加一条 KDE 曲线展示形状。
Python 中的核密度估计
在 Python 中,有多种方式计算和绘制 KDE,取决于您是需要快速出图还是要更精细地控制估计本身。
用 seaborn 可视化 KDE
获取 KDE 图的最快方式是 seaborn.kdeplot()。只需如下代码:
import seaborn as sns
import numpy as np
np. random. seed( 42 )
scores = np. concatenate( [
np. random. normal( 65 , 4 , 60 ) ,
np. random. normal( 80 , 3 , 40 )
] )
sns. kdeplot( scores, bw_adjust= 1 ) 技术支持
使用 seaborn 的 KDE
参数 bw_adjust 会缩放自动选择的带宽。小于 1 会让曲线更紧,超过 1 会让曲线更平滑。它是在 seaborn 内部带宽之上的一个倍数,因此您无需自己设定原始带宽值。
y 轴显示的是概率密度,而不是计数。曲线告诉您相对于整个分布来说某个数值有多可能。越高意味着那里数据越集中。
用 scipy 计算 KDE
如果您需要实际的密度数值——而不仅仅是图——可以使用 scipy.stats.gaussian_kde。它会返回一个可调用对象,您可以在任意点上进行评估。
from scipy. stats import gaussian_kde
import numpy as np
import matplotlib. pyplot as plt
kde = gaussian_kde( scores, bw_method= "scott" )
x = np. linspace( 45 , 100 , 500 )
density = kde( x)
plt. plot( x, density) 技术支持
bw_method="scott" 使用 Scott 法则自动选择带宽。这在大多数情况下是不错的默认值。您也可以传入一个标量手动设置带宽。
使用 scipy 与 matplotlib 的 KDE
R 中的核密度估计
在 R 中,KDE 内置于基础语言,无需额外包。
用 density() 计算 KDE
函数 density() 接受一个数值向量并返回 KDE 对象。
set.seed( 42 )
scores <- c( rnorm( 60 , mean = 65 , sd = 4 ) ,
rnorm( 40 , mean = 80 , sd = 3 ) )
kde <- density( scores, bw = "SJ" ) 技术支持
参数 bw 控制带宽选择。"SJ" 使用 Sheather–Jones 方法,相比默认值更适合处理多峰分布。您也可以传入数值手动设置带宽。
结果是一个列表对象,包含两个关键组件:
kde$x: 进行密度评估的一系列点
kde$y: 对应的密度值
绘制曲线
将结果直接传给 plot() 即可。
plot( kde,
main = "Exam Score Distribution" ,
xlab = "Score" ,
ylab = "Density" ) 技术支持
在 R 中绘制的 KDE
要在直方图上叠加 KDE,先用 hist() 并设定 freq = FALSE,然后用 lines() 添加曲线。
hist( scores, freq = FALSE , main = "Histogram + KDE" , xlab = "Score" )
lines( kde, col = "blue" , lwd = 2 ) 技术支持
R 中的直方图与 KDE
freq = FALSE 会将直方图按密度缩放,使柱形与曲线共享同一 y 轴。
KDE 的优点与局限
KDE 确实是很有用的可视化手段,但和任何方法一样,在用它替代直方图之前,值得了解其中的取舍。
优点
最大优点在于 KDE 不对数据分布做假设。您无需事先决定数据是否正态、指数或其他类型。形状来自数据本身,使 KDE 足够灵活,可处理多峰分布及其他不符合标准参数形式的情况。
其输出是一条平滑、连续的曲线,而非台阶式近似。这更便于发现模式——如多峰或长尾——而这些可能会因直方图的分箱选择而被遮蔽。
且由于 KDE 直接作用于原始数据,无需先拟合模型,它是任何探索性分析的良好第一步。
局限
带宽选择是主要弱点。若选得不当,估计要么追逐噪声,要么把真实模式抹平。像 Silverman 经验法则这样的自动方法对近似正态的数据效果不错,但在复杂分布下可能误导您。通常需要手动检查几个带宽值,才能对结果放心。
在大规模数据上,性能可能成为问题。KDE 需要在每个评估位置对每个数据点计算一次核函数,因此随着数据集变大,计算量会快速增长。对于大多数探索性工作这不是问题,但在包含几十万点的数据上可能会变慢。
边界效应更为微妙。标准 KDE 假设数据可在两个方向上无限延伸。当数据存在硬边界——如不能小于零的取值——估计会将概率质量“泄漏”到边界之外,从而使边缘附近的曲线被人为压低。存在边界校正版本的 KDE,但在标准库中较少实现。
结论
相比直方图,KDE 为查看数据分布提供了更干净的方式。无需分箱选择,也无需参数假设——只有一条展示数据集中实际内容的平滑曲线。
带宽是唯一真正重要的参数。尝试几个取值、比较曲线、使用自动选项,并在下结论前确保估计与您对数据的认知一致。
建立 KDE 直觉的最佳方法是把它用在真实数据上。选一个您熟悉的数据集,应用 KDE,并与直方图对比,看看此前忽略了什么。
对数据可视化感兴趣?如果您使用 Python,请查看我们的课程 用 Seaborn 进行数据可视化 ;如果您使用 R,请查看 用 ggplot2 进行数据可视化 。
尝试可视化一个分布时,是否遇到过这样的问题:每次调整直方图的分箱大小,图形的形状就变了?
通常是这样的。您选 10 个箱,看起来像一条平滑的曲线;换成 30 个箱,就出现了多个峰。数据没变,但不同的分箱数会给出不同的解读。这是直方图最大的毛病:它并不展示“分布”本身,而是展示某一种版本;而这种版本受到您随机设定的参数影响。
KDE(核密度估计)采用了不同的方法。它不把数据切分进箱,而是在每个数据点上放置一条小而平滑的曲线,然后把它们加总。这会给出一个对背后分布的单一、连续的估计。
本文将带您建立 KDE 的直觉、走读其公式、解释带宽如何控制平滑度,并提供 Python 和 R 的实用示例。
还不熟悉直方图?这里有一份全面指南:频率直方图,助您快速上手。
什么是核密度估计?
核密度估计是一种非参数方法,用于估计数据集的概率密度函数。
“非参数”正是它的不同之处。
参数方法需要假设数据服从某个特定分布——如正态、指数——然后拟合参数去匹配。如果假设错了,模型就错了。KDE 不做这样的假设。它让数据自己“发声”,直接从观测构建对底层分布的估计。
输出是一条平滑曲线,展示数值可能落在哪里——以及有多大可能。曲线的高点意味着密集区域,低点意味着稀疏区域。
为什么要用核密度估计?
直方图是可视化分布的默认工具,但它有个问题:您看到的形状取决于您选择的分箱数量。而这个分箱参数是由您来定。两个人看同一数据集,仅仅因为分箱数不同,就可能得出完全不同的结论。
使用 KDE,不再强行把数据塞进箱里,而是生成一条平滑、连续的曲线,不会因为您事先设定的任意参数而改变。
因此它在以下方面很有用:
KDE 的直观理解
对每个数据点放置一条小而平滑的曲线,这条曲线称为核(kernel)。然后,把这些单独的曲线全部相加。
最终得到一条展示数据密度的平滑曲线。数据点聚集的地方,多条核会重叠并叠加,曲线就会上升;数据稀疏的地方,核几乎不重叠,曲线就保持较低。每个点对最终估计的贡献都是相同的。
想象您记录了一门课学生的期末成绩。与其用直方图分箱,KDE 会在每个分数上放一条小而平滑的曲线。分数聚集的地方——比如 70–75 分附近——曲线会叠加上升;而一个考了 95 分的学生,只会在尾部加出一个小凸起。
下图正是这种效果。大多数学生集中在平均分附近,且有一位学生分数高得多:
KDE 可视化
核密度估计公式
KDE 的公式看起来比实际难。
KDE 公式
各部分含义如下:
n是数据点的数量x_i是数据集中各个具体的数据点K是核函数——放在每个点上的平滑曲线h是带宽——控制每个核的宽度x是您要评估密度的位置通俗地说,该公式表示:对于任意一点
x,看每个数据点x_i离它有多近,用核函数K对这种“接近程度”加权,并在全部n个点上取平均。对范围内的每个x都这么做,就得到完整的密度曲线。带宽
h位于K内部分数的分母。较小的h使核更窄,因此只有非常近的点会影响估计;较大的h会扩大影响范围。稍后将详细介绍。什么是核函数?
核就是您放在每个数据点上的平滑曲线。它定义了该点的影响如何向邻近点扩散。
每个核都以某个数据点为中心,并根据距离分配权重。越靠近中心的点权重越高,越远的点权重越低,甚至为零。具体的加权形状取决于您选择的核。
常见的三种选择:
多数情况下,核的选择影响不大。对同一数据、用相同带宽,两个不同的核通常会产生几乎相同的曲线。真正更重要的是带宽——我们接下来就看它。
带宽在 KDE 中的作用
带宽是对 KDE 输出影响最大的单一参数,甚至超过核的选择。
它控制每个核的宽度。窄核只吸收附近点的影响,宽核则把影响扩散到更大的范围。结果要么是紧贴数据的曲线,要么是更平滑的曲线。
小带宽
小带宽会让每个核紧而窄。估计会对每个数据点产生剧烈反应,这意味着既能捕捉到数据的真实结构,也会拾取噪声。
在实践中,这看起来像是一条多处尖峰的曲线。其中一些峰反映了真实聚类,另一些只是平滑不足造成的伪影。难点在于很难区分二者。
小带宽的 KDE
大带宽
大带宽会让每个核更宽。相邻核大量重叠,最终曲线会更平滑。
如果过于平滑,就会失去真实结构。两个明显的聚类可能被抹成一条曲线;厚尾分布可能看起来对称。可视化反而可能在“藏”信息。
大带宽的 KDE
如何找到合适的带宽
没有普适正确的带宽。目标是在足以滤掉噪声的同时,不至于把真实模式抹平。
大多数库提供自动带宽选择方法,其中Silverman 经验法则最常见。它根据样本量和数据的标准差选择带宽。对近似正态分布效果好,但可能对多峰分布过度平滑。
如果拿不准,可以尝试几个带宽值并比较曲线。差异会告诉您很多关于数据的信息。
KDE 与直方图
直方图和 KDE 都能展示数据的分布——但方式截然不同。
直方图
直方图把数据划分到离散的箱中,并统计每个箱中点的数量。它快速、直观,易于向非技术受众解释。
问题在于对分箱的敏感性。只要改变箱数,形状就变了。没有客观正确的分箱数量,这意味着两个人看同一数据,仅因这个选择不同就会得出不同结论。
直方图还会产生台阶状、不连续的形状。用于快速查看还好,但可能遮蔽真实的底层分布。
KDE
KDE 给出的是没有分箱参与的平滑、连续曲线。它更擅长揭示分布的真实形状——诸如偏态、多峰或厚尾等,而直方图可能因为分箱选择而忽略或误导。
代价是 KDE 引入了自己的参数——带宽——并且计算量更大。它也不太直观,因为 y 轴显示的是概率密度而不是计数,这可能会让不熟悉该概念的读者困惑。
各自何时使用
当您需要对数据进行快速、易解释的总结,或受众不熟悉密度估计时,用直方图;当分布形状很重要——比如要比较不同组,或要检测数据中的多峰——则使用 KDE。
直方图与 KDE 对比
实践中,它们常常结合使用:直方图显示计数,叠加一条 KDE 曲线展示形状。
Python 中的核密度估计
在 Python 中,有多种方式计算和绘制 KDE,取决于您是需要快速出图还是要更精细地控制估计本身。
用 seaborn 可视化 KDE
获取 KDE 图的最快方式是
seaborn.kdeplot()。只需如下代码:使用 seaborn 的 KDE
参数
bw_adjust会缩放自动选择的带宽。小于 1 会让曲线更紧,超过 1 会让曲线更平滑。它是在 seaborn 内部带宽之上的一个倍数,因此您无需自己设定原始带宽值。y 轴显示的是概率密度,而不是计数。曲线告诉您相对于整个分布来说某个数值有多可能。越高意味着那里数据越集中。
用 scipy 计算 KDE
如果您需要实际的密度数值——而不仅仅是图——可以使用
scipy.stats.gaussian_kde。它会返回一个可调用对象,您可以在任意点上进行评估。bw_method="scott"使用 Scott 法则自动选择带宽。这在大多数情况下是不错的默认值。您也可以传入一个标量手动设置带宽。使用 scipy 与 matplotlib 的 KDE
R 中的核密度估计
在 R 中,KDE 内置于基础语言,无需额外包。
用 density() 计算 KDE
函数
density()接受一个数值向量并返回 KDE 对象。参数 bw 控制带宽选择。
"SJ"使用 Sheather–Jones 方法,相比默认值更适合处理多峰分布。您也可以传入数值手动设置带宽。结果是一个列表对象,包含两个关键组件:
kde$x: 进行密度评估的一系列点kde$y: 对应的密度值绘制曲线
将结果直接传给
plot()即可。在 R 中绘制的 KDE
要在直方图上叠加 KDE,先用
hist()并设定freq = FALSE,然后用lines()添加曲线。R 中的直方图与 KDE
freq = FALSE会将直方图按密度缩放,使柱形与曲线共享同一 y 轴。KDE 的优点与局限
KDE 确实是很有用的可视化手段,但和任何方法一样,在用它替代直方图之前,值得了解其中的取舍。
优点
最大优点在于 KDE 不对数据分布做假设。您无需事先决定数据是否正态、指数或其他类型。形状来自数据本身,使 KDE 足够灵活,可处理多峰分布及其他不符合标准参数形式的情况。
其输出是一条平滑、连续的曲线,而非台阶式近似。这更便于发现模式——如多峰或长尾——而这些可能会因直方图的分箱选择而被遮蔽。
且由于 KDE 直接作用于原始数据,无需先拟合模型,它是任何探索性分析的良好第一步。
局限
带宽选择是主要弱点。若选得不当,估计要么追逐噪声,要么把真实模式抹平。像 Silverman 经验法则这样的自动方法对近似正态的数据效果不错,但在复杂分布下可能误导您。通常需要手动检查几个带宽值,才能对结果放心。
在大规模数据上,性能可能成为问题。KDE 需要在每个评估位置对每个数据点计算一次核函数,因此随着数据集变大,计算量会快速增长。对于大多数探索性工作这不是问题,但在包含几十万点的数据上可能会变慢。
边界效应更为微妙。标准 KDE 假设数据可在两个方向上无限延伸。当数据存在硬边界——如不能小于零的取值——估计会将概率质量“泄漏”到边界之外,从而使边缘附近的曲线被人为压低。存在边界校正版本的 KDE,但在标准库中较少实现。
结论
相比直方图,KDE 为查看数据分布提供了更干净的方式。无需分箱选择,也无需参数假设——只有一条展示数据集中实际内容的平滑曲线。
带宽是唯一真正重要的参数。尝试几个取值、比较曲线、使用自动选项,并在下结论前确保估计与您对数据的认知一致。
建立 KDE 直觉的最佳方法是把它用在真实数据上。选一个您熟悉的数据集,应用 KDE,并与直方图对比,看看此前忽略了什么。
对数据可视化感兴趣?如果您使用 Python,请查看我们的课程用 Seaborn 进行数据可视化;如果您使用 R,请查看用 ggplot2 进行数据可视化。