Другие ответы - все хорошие подходы.Тем не менее, есть несколько других опций в R, которые не были упомянуты, в том числе lowess
и 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)))
Вот данные, наложенные на сигмовидную кривую, которая их сгенерировала:
![data](https://i.stack.imgur.com/N70sI.png)
Этот вид данныхчасто встречается при взгляде на бинарное поведение среди населения.Например, это может быть график зависимости того, приобрел ли клиент что-либо (двоичный код 1/0 по оси Y) и сколько времени он провел на сайте (ось 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"))
![Fits](https://i.stack.imgur.com/wDBiO.png)
Как выКак видно, 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
, хотя все еще работает довольно быстро (в 15 раз быстрее, чем лесс).
Loess
также становится все более заторможенным по мере увеличения количества точек, становясь непригодным для использования около 50 000.
РЕДАКТИРОВАТЬ: дополнительные исследования показывают, что loess
дает лучшее соответствие для определенных наборов данных.Если вы работаете с небольшим набором данных, или производительность не учитывается, попробуйте обе функции и сравните результаты.