【发布时间】:2021-08-03 22:45:13
【问题描述】:
我正在实现一个函数来估计单变量和多变量情况下的核密度估计。就此而言,我使用的是高斯内核,即使处理大量数据集,它也能很好地工作。然而,许多人声称我应该使用 Epanechnikov 内核,因为它的计算效率更高,因为它支持紧凑。但我不同意,或者,至少,我还没有找到一种方法来实现它,以便它击败高斯。 这是我的代码,用于对实数中点 x_o 处的密度进行高斯估计,相对于值 x 的向量:
dens_point <- function(x_0, x, width){
weights <- (1/sqrt(2*pi))*exp(-(1/2)*(((x_0-x)/width)^2))
return((1/(length(x)*width))*sum(weights))
}
甚至更高效,
dens_point <- function(x_0, x, width){
constant <- (1/sqrt(2*pi)
weights <- constant*exp(-0.5*(((x_0-x)/width)^2)))
return((1/(length(x)*width))*sum(weights))
}
或者更进一步,以牺牲可读性为代价:
dens_point <- function(x_0, x, width){
constant <- (1/sqrt(2*pi)
return(
(1/(length(x)*width))*sum(constant*exp(-0.5*(((x_0-x)/width)^2))))
)
}
为了获得区间上的线,我只需对参数x_0 上的函数进行矢量化,并给它一个值序列。这是我能带来的效率。相比之下,Epanechnikov 内核要慢得多。我试过以下代码:
epanechnikov <- function(u){
if (u <= 1){
return(0)
} else {
return( (1-u^2)*0.75 )
}
}
epanechnikov <- Vectorize(epanechnikov)
dens_point <- function(x0, x, width){
weights <- epanechnikov( (x0-x)/width )
return( (1/(length(x)*width)*sum(weights) )
}
但是这个解比高斯解差到极点,却是我能想到的最精炼的表达方式。 For 循环和 sapplies 甚至更慢。我想说高斯函数非常快,因为它使用了基本的 R 向量运算,这是 Vectorize() 无法与之竞争的。你能想出一个更快的代码吗?
【问题讨论】:
-
要利用 Epanechnikov 内核的有界支持,需要能够有效地确定哪些点属于支持(因此您排除任何其他点)。这样做可能意味着用于存储数据点的专用结构(可能是一种树),因此在有限区域中查找数据点不需要扫描所有点(否则您将返回与成比例的操作数量数据的数量)。遇到这么多麻烦可能意味着相当大的数据集(数百万到数十亿)。
-
@RobertDodier 我非常同意。我最好的选择可能是首先对值进行排序,然后开始计算权重,当达到最后一个值严格为正且当前值为零的点时,然后停止并将以下所有点设为零价值。
标签: r statistics kernel-density