Все остальные ответы - хорошие подходы. Однако в 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)))
Вот данные, наложенные на сигмовидную кривую, которая их сгенерировала:
Такие данные являются обычным явлением при рассмотрении бинарного поведения среди населения. Например, это может быть график того, купил ли клиент что-либо (двоичное значение 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"))
Как видите, 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
лучше подходит для определенных наборов данных. Если вы имеете дело с небольшим набором данных или производительность не важна, попробуйте обе функции и сравните результаты.