其他答案都是很好的方法。但是,R 中还有一些其他选项未被提及,包括lowess
and approx
,它们可能会提供更好的拟合或更快的性能。
使用备用数据集更容易证明这些优势:
sigmoid <- function(x)
{
y<-1/(1+exp(-.15*(x-100)))
return(y)
}
dat<-data.frame(x=rnorm(5000)*30+100)
dat$y<-as.numeric(as.logical(round(sigmoid(dat$x)+rnorm(5000)*.3,0)))
这是与生成它的 sigmoid 曲线叠加的数据:

在查看人群中的二元行为时,这种数据很常见。例如,这可能是客户是否购买某物(y 轴上的二进制 1/0)与他们在网站上花费的时间(x 轴)的图。
大量的点用于更好地展示这些功能的性能差异。
Smooth
, spline
, 并且smooth.spline
都在像这样的数据集上使用我尝试过的任何参数集产生乱码,这可能是因为它们倾向于映射到每个点,这不适用于嘈杂的数据。
、和函数都产生有用的结果loess
,虽然只是勉强. 这是每个使用轻微优化参数的代码:lowess
approx
approx
loessFit <- loess(y~x, dat, span = 0.6)
loessFit <- data.frame(x=loessFit$x,y=loessFit$fitted)
loessFit <- loessFit[order(loessFit$x),]
approxFit <- approx(dat,n = 15)
lowessFit <-data.frame(lowess(dat,f = .6,iter=1))
结果:
plot(dat,col='gray')
curve(sigmoid,0,200,add=TRUE,col='blue',)
lines(lowessFit,col='red')
lines(loessFit,col='green')
lines(approxFit,col='purple')
legend(150,.6,
legend=c("Sigmoid","Loess","Lowess",'Approx'),
lty=c(1,1),
lwd=c(2.5,2.5),col=c("blue","green","red","purple"))

如您所见,lowess
产生了与原始生成曲线近乎完美的拟合。 Loess
很接近,但在两条尾巴上都出现了奇怪的偏差。
尽管您的数据集会非常不同,但我发现其他数据集的表现相似,两者都有loess
并且lowess
能够产生良好的结果。当您查看基准时,差异变得更加显着:
> microbenchmark::microbenchmark(loess(y~x, dat, span = 0.6),approx(dat,n = 20),lowess(dat,f = .6,iter=1),times=20)
Unit: milliseconds
expr min lq mean median uq max neval cld
loess(y ~ x, dat, span = 0.6) 153.034810 154.450750 156.794257 156.004357 159.23183 163.117746 20 c
approx(dat, n = 20) 1.297685 1.346773 1.689133 1.441823 1.86018 4.281735 20 a
lowess(dat, f = 0.6, iter = 1) 9.637583 10.085613 11.270911 11.350722 12.33046 12.495343 20 b
Loess
非常慢,需要 100 倍的时间approx
。 Lowess
产生比 更好的结果approx
,同时仍然运行得相当快(比 loess 快 15 倍)。
Loess
随着点数的增加,也变得越来越陷入困境,在 50,000 左右变得无法使用。
编辑:额外的研究表明,loess
它更适合某些数据集。如果您正在处理小型数据集或不考虑性能,请尝试这两个函数并比较结果。