来自R Documentation ...
bw.nrd0实现了选择a的带宽的经验法则 高斯核密度估计。默认为0.9倍 最小标准偏差和四分位数范围划分 样本大小的1.34倍到负的五分之一功率(= 西尔弗曼的“经验法则”,西尔弗曼(1986年,第48页,方程(3.31)) 除非四分位数与正数结果重合 保证。
在1到400(相当于np.arange(1,401)
)的数组上,nrd0将返回31.39367。当我尝试在python中实现类似的东西时......
def nrd0_python(x):
X = min(np.std(x), np.percentile(x,25))
top = 0.9*X
bottom = 1.34*len(x)**(-0.2)
return top/bottom
我高达200(准确地说,224.28217762858455)
对于silverman的经验法则,是否有任何已知的python函数?
答案 0 :(得分:3)
英语句子中操作符的优先级不明确。
这是一个返回您期望的值的实现:
In [201]: x = np.arange(1, 401)
In [202]: 0.9*min(np.std(x, ddof=1), (np.percentile(x, 75) - np.percentile(x, 25))/1.349)*len(x)**(-0.2)
Out[202]: 31.393668650034652
我没有Silverman参考。我在http://darp.lse.ac.uk/papersdb/Cowell-Flachaire_Handbook.pdf(第21页)中找到了。
答案 1 :(得分:2)
您没有正确的IQR计算:
import numpy
def bw_nrd0(x):
if len(x) < 2:
raise(Exception("need at least 2 data points"))
hi = numpy.std(x, ddof=1)
q75, q25 = numpy.percentile(x, [75 ,25])
iqr = q75 - q25
lo = min(hi, iqr/1.34)
if not ((lo == hi) or (lo == abs(x[0])) or (lo == 1)):
lo = 1
return 0.9 * lo *len(x)**-0.2
返回与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)
}
<bytecode: 0x0000000010c688b0>
<environment: namespace:stats>
编辑:我对if
代码中第二个R
语句的原始读数不正确,请参阅this question。它旨在捕获lo == 0
(因为sd(x) == 0
)的情况,在这种情况下,向量全部为零。如果我的理解是正确的,那应该是:
if not lo:
if hi:
lo = hi
elif abs(x[0]):
lo = abs(x[0])
else:
lo = 1
与R
代码一样,您可以将其缩短为:
lo = lo or hi or abs(x[0]) or 1
包括这些检查以及检查向量的长度非常重要。
答案 2 :(得分:-1)
如果您正在使用KDE,可以使用scipy.stats.gaussian_kde吗?它实现了Silverman和Scott的带宽选择规则。
http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.gaussian_kde.html