Le altre risposte sono tutti buoni approcci. Tuttavia, ci sono alcune altre opzioni in R che non sono state menzionate, tra cui lowess
e approx
, che potrebbero fornire adattamenti migliori o prestazioni più veloci.
I vantaggi si dimostrano più facilmente con un set di dati alternativo:
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)))
Ecco i dati sovrapposti alla curva sigmoidea che lo ha generato:
Questo tipo di dati è comune quando si osserva un comportamento binario tra una popolazione. Ad esempio, questo potrebbe essere un grafico che indica se un cliente ha acquistato o meno qualcosa (un 1/0 binario sull'asse y) rispetto alla quantità di tempo che ha trascorso sul sito (asse x).
Un gran numero di punti viene utilizzato per dimostrare meglio le differenze di prestazioni di queste funzioni.
Smooth
, spline
E smooth.spline
tutto senza senso produrre su un set di dati come questo con qualsiasi insieme di parametri ho cercato, forse a causa della loro tendenza a mappare ogni punto, che non funziona per i dati rumorosi.
I loess
, lowess
e approx
funzioni di tutti producono risultati utili, anche se appena per approx
. Questo è il codice per ciascuno che utilizza parametri leggermente ottimizzati:
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))
E i risultati:
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"))
Come puoi vedere, lowess
produce un adattamento quasi perfetto alla curva di generazione originale. Loess
è vicino, ma sperimenta una strana deviazione su entrambe le code.
Sebbene il tuo set di dati sarà molto diverso, ho scoperto che altri set di dati si comportano in modo simile, con entrambi loess
e in lowess
grado di produrre buoni risultati. Le differenze diventano più significative quando guardi i benchmark:
> 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
è estremamente lento, impiegando 100 volte il tempo approx
. Lowess
produce risultati migliori rispetto a approx
, pur essendo ancora in esecuzione abbastanza rapidamente (15 volte più veloce di loess).
Loess
inoltre diventa sempre più impantanato all'aumentare del numero di punti, diventando inutilizzabili intorno ai 50.000.
MODIFICA: ulteriori ricerche mostrano che si loess
adattano meglio a determinati set di dati. Se hai a che fare con un piccolo set di dati o le prestazioni non sono una considerazione, prova entrambe le funzioni e confronta i risultati.