Pozostałe odpowiedzi to dobre podejścia. Jest jednak kilka innych opcji w R, o których nie wspomniano, w tym lowess
i approx
, które mogą zapewnić lepsze dopasowanie lub szybszą wydajność.
Zalety można łatwiej wykazać za pomocą alternatywnego zestawu danych:
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)))
Oto dane nałożone na sigmoidalną krzywą, która ją wygenerowała:
Ten rodzaj danych jest powszechny, gdy patrzy się na zachowanie binarne wśród populacji. Na przykład może to być wykres przedstawiający, czy klient coś kupił (wartość binarna 1/0 na osi y) w porównaniu z czasem spędzonym w witrynie (oś x).
Aby lepiej pokazać różnice w działaniu tych funkcji, używa się dużej liczby punktów.
Smooth
, spline
i smooth.spline
wszystkie generują bełkot na takim zbiorze danych z dowolnym zestawem parametrów, które wypróbowałem, być może z powodu ich tendencji do mapowania do każdego punktu, co nie działa w przypadku zaszumionych danych.
Te loess
, lowess
oraz approx
funkcje produkują użytecznych wyników, chociaż ledwo za approx
. Oto kod dla każdego z lekko zoptymalizowanymi parametrami:
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))
A wyniki:
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"))
Jak widać, lowess
daje prawie idealne dopasowanie do oryginalnej krzywej generowania. Loess
jest blisko, ale doświadcza dziwnego odchylenia na obu ogonach.
Chociaż Twój zestaw danych będzie bardzo różny, odkryłem, że inne zestawy danych działają podobnie, z obydwoma loess
i lowess
zdolnymi do generowania dobrych wyników. Różnice stają się bardziej znaczące, gdy spojrzysz na testy porównawcze:
> 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
jest niezwykle powolny, trwa 100 razy dłużej approx
. Lowess
daje lepsze wyniki niż approx
, podczas gdy nadal działa dość szybko (15x szybciej niż less).
Loess
również staje się coraz bardziej grzęznąć w miarę wzrostu liczby punktów, a około 50 000 staje się bezużytecznych.
EDYTUJ: Dodatkowe badania pokazują, że loess
zapewnia lepsze dopasowanie do niektórych zestawów danych. Jeśli masz do czynienia z małym zestawem danych lub wydajność nie jest brana pod uwagę, wypróbuj obie funkcje i porównaj wyniki.