为什么正态分布向量的核密度估计具有非平滑二阶导数?

机器算法验证 r 内核平滑
2022-03-30 04:37:39

我有一些正态分布的数据:

mu <- 3
sigma <- 5
x <- rnorm(1e5, mu, sigma)

我用相当高的带宽进行了内核密度估计:

kernel_density_of_x <- density(x, bw = 5)

然后我区分了它:

differentiate <- function(x, y)
{
  diffOfX <- diff(x)
  data.frame(
    x      = x[-length(x)] + (diffOfX / 2), 
    dyByDx = diff(y) / diffOfX
  )
}

first_derivative <- with(kernel_density_of_x, differentiate(x, y))

这看起来和预期的一样:

library(ggplot2)
(p1 <- ggplot(first_derivative, aes(x, dyByDx)) + geom_line())

正如预期的那样,一阶导数看起来很平滑

当我再次进行微分时,我期待另一条平滑曲线,但我看到了奇怪的周期性效应。

second_derivative <- with(first_derivative, differentiate(x, dyByDx))
(p2 <- p1 %+% second_derivative + ylab("d2yByDx2"))

二阶导数出乎意料地嘈杂

我尝试了几个不同的kernel参数选项,但噪音仍然存在。
例如,将带宽降低到 会0.5产生主导绘图的较低频率噪声(使其毫无意义)。

减少采样点的数量n = 512n = 32停止问题,但这会导致其他问题。

为什么会出现这种效果?它是功能的工件density,还是我做了一些愚蠢的事情?


我们可以使用生成的正态分布的概率密度函数重新绘制绘图x,以查看我预期的形状:

xx <- seq.int(-20, 20, 0.1)
pdf_of_xx <- dnorm(xx, mu, sigma)
first_derivative_of_xx <- differentiate(xx, pdf_of_xx)
second_derivative_of_xx<- with(first_derivative_of_xx, differentiate(x, dyByDx))
ggplot(second_derivative_of_xx, aes(x, dyByDx)) + geom_line()

直接从概率密度函数创建的二阶导数是平滑的

2个回答

正如whuber 评论的那样,您所看到的是由于使用的近似值(通过快速傅立叶变换)density

如果您通过蛮力计算内核密度估计并将其与density给出的估计进行比较,您将在差异中看到这种循环模式。

结果的第二个差异导致density效果被夸大。与蛮力内核密度估计的第二个差异没有显示出这种模式,但计算速度要慢 3 个数量级。

我在这个要点中放了一些代码我的蛮力内核密度估计如下:

mydensity <-
function(dat, x, bw=5) # dat=the data; x=points to calculate density estimate
{
  y <- vapply(x, function(a) mean(dnorm(a, dat, bw)), 1)
  data.frame(x=x, y=y)
}

这是第二个差异的图片,蓝色density来自蛮力方法,红色来自蛮力方法。 在此处输入图像描述

在要点的代码中,您使用了硬输入的带宽 ( bw=5),这与返回的最佳带宽非常不同,例如:

library(ks)
h <- hpi(x)

这实际上是关于h=0.85

bw在设置为的地方执行代码很有趣h那么最终的图如下。这里的差异不是那么大。 在此处输入图像描述