散点图内核平滑:ksmooth() 根本不平滑我的数据

Scatter plot kernel smoothing: ksmooth() does not smooth my data at all

原题

我想平滑我的解释变量,比如车辆的速度数据,然后使用这个平滑值。我搜索了很多,没有找到直接的答案。

我知道如何计算核密度估计(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

这是一个散点图:

我想针对 t 平滑 speed,并且我想为此目的使用内核平滑。按照@Zheyuan的建议,我应该用ksmooth():

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

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

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

为什么会这样?谢谢!

老问题的答案


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

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

x <- rnorm(1000, 0, 1)

我们可以通过核密度估计器评估其分布:

k <- density(x)
plot(k); rug(x)

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

kernel smoother,其实是回归问题,或者散点图平滑问题。您需要两个变量:一个响应变量 y 和一个解释变量 x。让我们使用上面的 x 作为解释变量。对于响应变量 y,我们从

生成一些玩具值
y <- sin(x) + rnorm(1000, 0, 0.2)

给定 yx 之间的散点图:

我们想找到一个平滑函数来近似那些散点。

带有 R 函数的 Nadaraya-Watson 核回归估计 ksmooth() 将帮助您:

s <- ksmooth(x, y, kernel = "normal")
plot(x,y, main = "kernel smoother")
lines(s, lwd = 2, col = 2)

如果你想用预测来解释一切:

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

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


你真的有时间序列吗?

一辆车的速度”听起来像是您正在监控 speed 时间 t。如果是,得到speedt之间的散点图,并使用ksmooth().

其他平滑方法如loess()smooth.spline()不是内核平滑class,但你可以比较。

对重新编辑的问题的回答

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 的时间序列数据,这意味着 (i-0.5, i+0.5) 附近没有其他 speed 数据,时间 t = i,除了 speed[i] .结果,没有做局部加权平均!

您需要选择更大的带宽。例如,如果我们希望平均超过 20 个值,我们应该设置 bandwidth = 10(不是 20,因为它是双侧的)。这就是我们得到的:

fit <- ksmooth(vehicle$t, vehicle$speed, bandwidth = 10)
plot(vehicle, cex = 0.5)
lines(fit,col=2,lwd = 2)

平滑度select离子

ksmooth() 的一个问题是您必须自己设置 bandwidth。您可以看到此参数极大地塑造了拟合曲线。大 bandwidth 使曲线平滑,但远离数据;而小带宽则相反。

有最优的bandwidth吗?有没有办法select最好的?

是的,使用 sm 包中的 sm.regression(),使用 selecting 带宽的交叉验证方法。

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

您可以检查 fit$h 是否为 18.7。

其他方法

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

我有一个答案:

  • 关于 smooth.spline();这个很有技术含量!
  • 关于 smooth.spline();这个是实用造型。
  • 关于 loess();这是关于 loess().
  • 的一般用途

在这里,我将演示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)

你真的需要阅读我上面的第一个 link,才能理解为什么我在第一种情况下使用 control.spar,而在第二种情况下不使用它。

更强大的包

我肯定会推荐 mgcv。关于 mgcv,我有几个答案,但我不想让您不知所措。所以,我不会在这里做扩展。学会很好地使用 ksmooth()smooth.spline()loess()。以后遇到更复杂的问题,回来stack overflow求助!