Les autres réponses sont toutes de bonnes approches. Cependant, il existe quelques autres options dans R qui n'ont pas été mentionnées, notamment lowess
et approx
, qui peuvent donner de meilleurs ajustements ou des performances plus rapides.
Les avantages sont plus facilement démontrés avec un autre jeu de données:
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)))
Voici les données superposées à la courbe sigmoïde qui l'a générée:
Ce type de données est courant lorsqu'on examine un comportement binaire au sein d'une population. Par exemple, il peut s'agir d'un graphique indiquant si un client a acheté quelque chose (un binaire 1/0 sur l'axe y) par rapport au temps passé sur le site (axe x).
Un grand nombre de points sont utilisés pour mieux démontrer les différences de performances de ces fonctions.
Smooth
, spline
et smooth.spline
tous produisent du charabia sur un ensemble de données comme celui-ci avec n'importe quel ensemble de paramètres que j'ai essayé, peut-être en raison de leur tendance à mapper vers chaque point, ce qui ne fonctionne pas pour les données bruyantes.
Les loess
, lowess
et les approx
fonctions produisent tous les résultats utilisables, bien que à peine pour approx
. Voici le code pour chacun utilisant des paramètres légèrement optimisés:
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))
Et les résultats:
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"))
Comme vous pouvez le voir, lowess
produit un ajustement presque parfait à la courbe génératrice d'origine. Loess
est proche, mais subit une étrange déviation des deux côtés.
Bien que votre ensemble de données soit très différent, j'ai trouvé que d'autres ensembles de données fonctionnent de la même manière, avec les deux loess
et lowess
capables de produire de bons résultats. Les différences deviennent plus significatives lorsque vous regardez les benchmarks:
> 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
est extrêmement lent, prenant 100 fois plus longtemps que approx
. Lowess
produit de meilleurs résultats que approx
, tout en fonctionnant assez rapidement (15x plus rapide que loess).
Loess
s'embourbe également de plus en plus à mesure que le nombre de points augmente, devenant inutilisable autour de 50 000.
EDIT: Des recherches supplémentaires montrent que cela loess
donne de meilleurs ajustements pour certains ensembles de données. Si vous avez affaire à un petit ensemble de données ou que les performances ne sont pas à prendre en considération, essayez les deux fonctions et comparez les résultats.