散点图核平滑:ksmooth()未对我的数据进行平滑处理

8

原问题

我想要平滑我的自变量,例如一辆车的速度数据,然后使用这些平滑值。我搜索了很多资料,但没有找到直接回答我的答案。

我知道如何计算核密度估计 (density()KernSmooth::bkde()),但是我不知道如何计算速度的平滑值。


重新编辑的问题

感谢@ZheyuanLi,我能更好地解释我拥有的内容以及我想要做什么。因此,我已经重新编辑了我的问题,如下:

我有一些车辆在某段时间内的速度测量值,存储为数据帧vehicle

         t       speed
1        0   0.0000000
2        1   0.0000000
3        2   0.0000000
4        3   0.0000000
5        4   0.0000000
.        .           .
.        .           .
1031  1030   4.8772222
1032  1031   4.4525000
1033  1032   3.2261111
1034  1033   1.8011111
1035  1034   0.2997222
1036  1035   0.2997222

这里是一个散点图:

scatter

我想要对 t 上的 speed 进行平滑,并且我想要使用核平滑法。根据 @Zheyuan 的建议,我应该使用 ksmooth()

fit <- ksmooth(vehicle$t, vehicle$speed)

然而,我发现平滑后的数值与我的原始数据完全相同:

sum(abs(fit$y - vehicle$speed))  # 0

为什么会发生这种情况?谢谢!

1
假设您有一个向量并在R中使用density函数。 您可以将其分配为Y<-density(Speed)并获取Y$y,这是平滑值。 - akash87
loess 函数通常用于非参数平滑。它具有一个预测方法。对于平滑计算 kde 没有太多意义,也许您应该发布一个例子。从未排序的值开始,对其进行排序并估计它们的局部“接近度”。 - IRTFM
我怀疑使用定向评论来拉票将会在更广泛的SO社区中受到负面看待。你可以考虑在MetaSO上进行搜索。 - IRTFM
@ZheyuanLi 我应该补充说,我对你最近的贡献印象非常深刻。许多高质量的答案。 - IRTFM
@ZheyuanLi 非常感谢您的帮助,现在我面临一个新问题,如果我想做非对称核函数,比如Gamma核函数怎么办? - hajar
显示剩余3条评论
2个回答

13

老问题的答案


您需要区分“核密度估计”和“核平滑”。

密度估计只适用于单一变量。它旨在估计该变量在其物理域上的分布情况。例如,如果我们有1000个正态样本:

x <- rnorm(1000, 0, 1)

我们可以通过核密度估计器来评估它的分布:
k <- density(x)
plot(k); rug(x)

密度

x轴上的地毯显示了您的x值的位置,而曲线则测量了这些地毯的密度。

核平滑器实际上是一个回归问题或散点图平滑问题。 您需要两个变量:一个响应变量y和一个解释变量x。 让我们使用上面的x作为解释变量。 对于响应变量y,我们从中生成一些玩具值

y <- sin(x) + rnorm(1000, 0, 0.2)

给定 yx 之间的散点图:

scatter

我们希望找到一个平滑的函数来近似这些散点。
使用 R 函数 ksmooth() 的 Nadaraya-Watson 核回归估计将有所帮助:
s <- ksmooth(x, y, kernel = "normal")
plot(x,y, main = "kernel smoother")
lines(s, lwd = 2, col = 2)

ks

如果你想以预测为基础来解释所有内容:

  • 核密度估计:给定x,预测x的密度;也就是说,我们有一个概率估计 P(grid[n] < x < grid[n+1]),其中grid是一些网格点;
  • 核平滑:给定x,预测y;也就是说,我们得到了一个函数的估计值f(x),它近似于y

在这两种情况下,你没有关于解释变量x的平滑值。所以你的问题:“我想平滑我的解释变量”是没有意义的。


你是否有时间序列数据?

“一个车辆的速度”听起来像是你正在监测speed沿着时间t的变化。如果是这样的话,在speedt之间绘制散点图,并使用ksmooth()

其他平滑方法,如loess()smooth.spline()不属于核平滑类,但你可以进行比较。


非常感谢您详细的解释,这让我对问题非常清楚。是的,没错,我有1202秒的速度数据,所以根据您的答案,我应该使用ksmooth(t,speed,....)吗? - hajar
非常感谢您的帮助。我使用了ksmooth(t,speed),但结果与Speed原始值相同。 - hajar
我添加了时间和速度数据。 - hajar
亲爱的哲远,我找到了问题所在,是带宽的问题,我已经更改了它,现在我从ksmooth得到了结果,再次非常感谢你的帮助。 - hajar

8

回答重新编辑的问题

ksmooth() 的默认带宽为 0.5:

 ksmooth(x, y, kernel = c("box", "normal"), bandwidth = 0.5,
         range.x = range(x),
         n.points = max(100L, length(x)), x.points)

对于具有滞后1的时间序列数据,这意味着在时间t=i时,邻域(i-0.5, i+0.5)中没有其他速度数据,除了speed[i]。因此,不进行局部加权平均!您需要选择更大的带宽。例如,如果我们希望对20个值进行平均,则应将带宽设置为10(而不是双侧的20)。这就是我们得到的结果:
fit <- ksmooth(vehicle$t, vehicle$speed, bandwidth = 10)
plot(vehicle, cex = 0.5)
lines(fit,col=2,lwd = 2)

enter image description here

平滑度选择

ksmooth() 存在一个问题,就是必须自己设置 bandwidth。您可以看到这个参数会显著地改变拟合的曲线形状。大的 bandwidth 会使曲线更加平滑,但离数据远;而小的 bandwidth 则反之。

有没有最佳的 bandwidth?有没有一种方法来选择最佳的呢?

有的,使用 sm 包的 sm.regression() 函数,并采用交叉验证法来选择带宽。

fit <- sm.regression(vehicle$t, vehicle$speed, method = "cv", eval.points = 0:1035)
## plot will be automatically generated!

enter image description here

您可以检查fit$h的值为18.7。

其他方法

也许您认为sm.regression()过度平滑了您的数据?那么,使用loess()或者我最喜欢的smooth.spline()

我有一些答案:

在这里,我将演示如何使用smooth.spline()

fit <- smooth.spline(vehicle$t, vehicle$speed, all.knots = TRUE, control.spar = list(low = -2, hight = 2))

# Call:
# smooth.spline(x = vehicle$t, y = vehicle$speed, all.knots = TRUE, 
#     control.spar = list(low = -2, hight = 2))

# Smoothing Parameter  spar= 0.2519922  lambda= 4.379673e-11 (14 iterations)
# Equivalent Degrees of Freedom (Df): 736.0882
# Penalized Criterion: 3.356859
# GCV: 0.03866391

plot(vehicle, cex = 0.5)
lines(fit$x, fit$y, col = 2, lwd = 2)

在此输入图片描述

或者使用它的回归样条版本:

fit <- smooth.spline(vehicle$t, vehicle$speed, nknots = 200)
plot(vehicle, cex = 0.5)
lines(fit$x, fit$y, col = 2, lwd = 2)

enter image description here

请先阅读我上面的第一个链接,以了解我在第一种情况下为什么使用control.spar,而在第二种情况下不需要。

更强大的软件包

我绝对推荐mgcv。我有关于mgcv的几个答案,但我不想压倒你。所以,我就不在这里扩展了。要学会很好地使用ksmooth()smooth.spline()loess()。将来,当你遇到更复杂的问题时,请回到stackoverflow寻求帮助!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接