我正在实现一个函数来估计单变量和多变量情况下的核密度估计。就此而言,我使用的是高斯内核,即使对于大量数据集,它也能很好地工作。然而许多人声称我应该使用 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 循环和应用甚至更慢。我想说高斯函数非常快,因为它使用基本 R 向量运算,这是 Vectorize() 无法与之竞争的。你能想出更快的代码吗?
确实,
Vectorize
无法与矢量化函数竞争。因此,只需利用基本函数即可:
epanechnikov2 <- function(u) {
k <- (1-u^2) * 0.75
k[u <= 1] <- 0
k
}
或者稍微快一点[编辑:并且使用更少的内存]:
epanechnikov3 <- function(u) {
k <- (1-u^2) * 0.75
(abs(k) + k) / 2
}
我不熟悉R的语法,但我相信提问者提到的更高效的场景只有当(x_0)规则排列时才会出现,比如在算术序列中。在这种情况下,根据 (x) 和宽度的值将 (x_0) 限制为一个窗口是非常方便的。