具有大数据集的 r 中的散点图平滑:不同的方法

机器算法验证 r 平滑 广义加法模型 黄土
2022-03-29 14:38:16

我有一个包含两个变量的大型数据集(>300,000 行)。y 是二进制的,x 是连续的和数字的。我想绘制 y 并针对 x 添加平滑曲线。我知道 loess(y~x) 是一个解决方案,但是由于我有这么大的数据集,所以即使我将 'cell' 参数设置为 500 也需要很长时间才能运行。

使用 scatter.smooth,它运行得更快,我认为它也使用黄土。但我无法理解参数'evaluation = 50'。这是否意味着它只使用 1/50 的数据来生成平滑曲线?

我还尝试使用 geom_smooth,它会自动切换到“method=gam”,因为我有超过 1000 个数据点。但曲线看起来与我使用 scatter.smooth 得到的曲线不同(我想这是正常的,因为它们是不同的模型)。

我的目标只是查看数据的模式。我应该使用哪种平滑方法?我可以信任 scatter.smooth 吗?使用 loess 和 gam 有什么区别?

下面是来自 scatter.smooth 的绘图。它看起来不错,但它的运行速度比常规的 loess() 快得多。我不确定它是如何工作的...... 在此处输入图像描述

使用 whuber 提供的方法: 在此处输入图像描述

任何帮助将不胜感激!

谢谢

2个回答

使用移动窗口均值平滑响应实际上是有效且准确的:这可以在整个数据集上通过快速傅里叶变换在几分之一秒内完成。出于绘图目的,请考虑对原始数据和平滑数据进行二次抽样。您可以进一步平滑二次采样平滑。这将比仅仅平滑二次采样数据更可靠。

通过多种方式实现对平滑强度的控制,为这种方法增加了灵活性:

  • 较大的窗口会增加平滑度。

  • 可以对窗口中的值进行加权以创建连续平滑。

  • 可以调整用于平滑子采样平滑的最低参数。


例子

首先让我们生成一些有趣的数据。它们存储在两个并行数组中,timesx(二进制响应)。

set.seed(17)
n <- 300000
times <- cumsum(sort(rgamma(n, 2)))
times <- times/max(times) * 25
x <- 1/(1 + exp(-seq(-1,1,length.out=n)^2/2 - rnorm(n, -1/2, 1))) > 1/2

这是应用于完整数据集的运行平均值。使用了相当大的窗口半角();这可以增加以获得更强的平滑度。内核具有高斯形状以使平滑合理地连续。该算法完全公开:在这里您可以看到内核显式构造并与数据进行卷积以生成平滑数组1172y

k <- min(ceiling(n/256), n/2)  # Window size
kernel <- c(dnorm(seq(0, 3, length.out=k)))
kernel <- c(kernel, rep(0, n - 2*length(kernel) + 1), rev(kernel[-1]))
kernel <- kernel / sum(kernel)
y <- Re(convolve(x, kernel))

让我们以内核半宽的一小部分间隔对数据进行二次采样,以确保不会忽略任何内容:

j <- floor(seq(1, n, k/3)) # Indexes to subsample

在示例j中,只有元素代表所有原始值。768300,000

代码的其余部分绘制了子采样原始数据、子采样平滑(灰色)、子采样平滑的低平滑(红色)和子采样数据的低平滑(蓝色)。最后一种方法虽然很容易计算,但比推荐的方法更易变化,因为它基于一小部分数据。

plot(times[j], x[j], col="#00000040", xlab="x", ylab="y")
a <- times[j]; b <- y[j]   # Subsampled data
lines(a, b, col="Gray")
f <- 1/6                   # Strength of the lowess smooths
lines(lowess(a, f=f)$y, lowess(b, f=f)$y, col="Red", lwd=2)
lines(lowess(times[j], f=f)$y, lowess(x[j], f=f)$y, col="Blue")

数字

红线(下采样窗口平均值的低平滑)是用于生成数据的函数的非常准确的表示。蓝线(子采样数据的低平滑度)表现出虚假的可变性。

我发现包中的locfit函数locfit是一个很好的解决方案 - 它速度很快,并且可以很容易地按组绘制 ( https://cran.r-project.org/web/packages/locfit/locfit.pdf )。scale、alpha、deg、kern、kt、acri 和基础参数控制平滑量。我用它geom_smoothgeom_smooth(method='locfit', method.args = list(deg=1, alpha=0.3))