对于什么是西尔弗曼规则似乎存在分歧。 TL;DR - scipy 使用了更糟糕的规则版本,该规则仅适用于正态分布的单峰数据。 R 使用更好的版本,“两全其美”并且“适用于广泛的密度”。
The scipy 文档说西尔弗曼规则是实施为:
def silverman_factor(self):
return power(self.neff*(self.d+2.0)/4.0, -1./(self.d+4))
Where d
是维数(1,在你的情况下)和neff
是有效样本量(点数,假设没有权重)。所以 scipy 带宽是(n * 3 / 4) ^ (-1 / 5)
(乘以标准差,以不同的方法计算)。
相比之下,Rstats包文档将 Silverman 的方法描述为“标准差和四分位数最小值的 0.9 倍除以样本量的 1.34 倍的负五次方”,也可以在 R 代码中进行验证,输入bw.nrd0
在控制台中给出:
function (x)
{
if (length(x) < 2L)
stop("need at least 2 data points")
hi <- sd(x)
if (!(lo <- min(hi, IQR(x)/1.34)))
(lo <- hi) || (lo <- abs(x[1L])) || (lo <- 1)
0.9 * lo * length(x)^(-0.2)
}
维基百科另一方面,将“西尔弗曼经验法则”作为估计器的许多可能名称之一:
1.06 * sigma * n ^ (-1 / 5)
wikipedia 版本相当于 scipy 版本。
所有三个来源(scipy 文档、维基百科和 R 文档)都引用了相同的原始参考文献:Silverman、B.W. (1986)。用于统计和数据分析的密度估计。伦敦:Chapman & Hall/CRC。 p。 48.ISBN 978-0-412-24620-3。维基百科和 R 特别引用了第 48 页,而 scipy 的文档没有提及页码。 (我已向维基百科提交了编辑,将其页面引用更新为第 45 页,见下文。)
阅读 Silverman 论文第 45 页,维基百科文章中使用的是方程 3.28:(4 / 3) ^ (1 / 5) * sigma * n ^ (-1 / 5) ~= 1.06 * sigma * n ^ (-1 / 5)
。 scipy使用同样的方法,重写(4 / 3) ^ (1 / 5)
作为等价的(3 / 4) ^ (-1 / 5)
。西尔弗曼描述了这种方法:
虽然(3.28)在总体确实是正态分布的情况下会很好地工作,但如果总体是多峰的,它可能会有些过度平滑......随着混合物变得更加强烈的双峰,相对于最佳选择,公式(3.28)将变得越来越过度平滑的平滑参数。
scipy 文档参考这个弱点,指出:
它包括自动带宽确定。该估计最适合单峰分布;双峰或多峰分布往往会过度平滑。
然而,Silverman 的文章继续改进了 scipy 使用的方法,以达到 R 和 Stata 使用的方法。在第 48 页,我们得到方程 3.31:
h = 0.9 * A * n ^ (-1 / 5)
# A defined on previous page, eqn 3.30
A = min(standard deviation, interquartile range / 1.34)
西尔弗曼将此方法描述为:
两全其美...总之,平滑参数的选择 ([eqn] 3.31) 对于各种密度都效果很好,并且评估起来很简单。对于许多用途来说,它肯定是窗口宽度的适当选择,而对于其他用途来说,这将是后续微调的良好起点。
因此,维基百科和 Scipy 似乎使用了 Silverman 提出的估计器的简单版本,但存在已知的弱点。 R和Stata使用更好的版本。