Las otras respuestas son todos buenos enfoques. Sin embargo, hay algunas otras opciones en R que no se han mencionado, incluidas lowess
y approx
, que pueden brindar mejores ajustes o un rendimiento más rápido.
Las ventajas se demuestran más fácilmente con un conjunto de datos 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)))
Aquí están los datos superpuestos con la curva sigmoidea que los generó:
Este tipo de datos es común cuando se observa un comportamiento binario entre una población. Por ejemplo, esto podría ser un gráfico de si un cliente compró algo (un 1/0 binario en el eje y) versus la cantidad de tiempo que pasó en el sitio (eje x).
Se utilizan una gran cantidad de puntos para demostrar mejor las diferencias de rendimiento de estas funciones.
Smooth
, spline
y smooth.spline
todos producen un galimatías en un conjunto de datos como este con cualquier conjunto de parámetros que haya probado, tal vez debido a su tendencia a mapear en todos los puntos, lo que no funciona para datos ruidosos.
Las loess
, lowess
y approx
las funciones de todos los resultados utilizables producen, aunque apenas para approx
. Este es el código para cada uno que usa parámetros ligeramente optimizados:
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))
Y los resultados:
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"))
Como puede ver, lowess
produce un ajuste casi perfecto a la curva generadora original. Loess
está cerca, pero experimenta una extraña desviación en ambas colas.
Aunque su conjunto de datos será muy diferente, he descubierto que otros conjuntos de datos funcionan de manera similar, con ambos loess
y lowess
capaces de producir buenos resultados. Las diferencias se vuelven más significativas cuando observa los puntos de referencia:
> 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
es extremadamente lento, tarda 100 veces más que approx
. Lowess
produce mejores resultados que approx
, sin dejar de correr bastante rápido (15 veces más rápido que loess).
Loess
También se empantana cada vez más a medida que aumenta el número de puntos, volviéndose inutilizables alrededor de 50.000.
EDITAR: La investigación adicional muestra que loess
ofrece mejores ajustes para ciertos conjuntos de datos. Si se trata de un conjunto de datos pequeño o el rendimiento no es una consideración, pruebe ambas funciones y compare los resultados.