Znajomy brał udział w projekcie, w którym na podstawie historii należało wykonać predykcję w przód cechy Y. Problem polegał na tym, że cecha Y wykazywała tendencje do wzrostu. Na potrzeby tego wpisu Y to może być mleczność krów lub zapotrzebowanie na energię czy cokolwiek innego co z czasem średnio rośnie.
Rozmawialiśmy trochę o tym co może się sprawdzić w tego typu analizach. Jako benchmark wykorzystaliśmy współczesne techniki pozwalające na podgrzanie procesora typu lasy losowe czy SVM. Okazuje się jednak (po fakcie, jest to nawet zgodne z intuicją ;-), że jeżeli występuje w miarę stabilny trend to zakres wartości obserwowanych w przyszłości może być inny niż zakres wartości obserwowanych w przeszłości. W tym przypadku techniki takie jak zwykła regresja liniowa mogą dać lepsze wyniki niż wspomniane SVM i RF.
Rozważmy taki przykład. Mamy do dyspozycji N predyktorów, chcemy przewidzieć rozwój cechy Y. W rzeczywistości ta cecha zależy tylko od pierwszego z N predyktorów. W szranki postawimy SVM, RandomForest, regresję liniową i regresję z regularyzacją typu lasso.
Przykład będzie czysto symulacyjny.
Zacznijmy od wylosowania danych, po 100 obserwacji i N=25 predyktorów. Zbiór testowy będzie poza domeną zbioru uczącego, wszystkie zmienne przesuwamy o +1.
library(dplyr) library(lasso2) library(e1071) library(randomForest) library(ggplot2) # will be useful in simulations getData <- function(n = 100, N = 25 ){ x <- runif(N*n) %>% matrix(n, N) # artificial out-of-domain [0-1] x_test <- x + 1 list(x = x, y = x[,1] * 5 + rnorm(n), x_test = x_test, y_test = x_test[,1] * 5 + rnorm(n)) } # let's draw a dataset gdata <- getData() head(gdata$y) # [1] -0.5331184 3.1140116 4.9557897 3.2433499 2.8986888 5.2478431 dim(gdata$x) # [1] 100 25 |
W wylosowanych danych zależność pomiędzy pierwszym predyktorem a Y jest liniowa, dodaliśmy małe zakłócenie losowe by nie być zbyt tendencyjnym.
with(gdata, qplot(x[,1], y) + geom_smooth(se=FALSE, method="lm") ) |
Wykonajmy dopasowanie modelu i policzmy MSE dla każdego z modeli.
Następnie powtórzmy losowanie i dopasowanie modeli 100 krotnie.
fitModels <- function(x, y) { ndata <- data.frame(y, x) list( model_lasso = l1ce(y ~ ., data=ndata), model_lm = lm(y ~ ., data=ndata), model_svm = svm(x, y), model_rf = randomForest(x, y)) } testModels <- function(models, x_test, y_test) { predict_lasso <- predict(models$model_lasso, data.frame(x_test)) predict_lm <- predict(models$model_lm, data.frame(x_test)) predict_svm <- predict(models$model_svm, x_test) predict_rf <- predict(models$model_rf, x_test) c( lasso = mean((predict_lasso - y_test)^2), lm = mean((predict_lm - y_test)^2), rf = mean((predict_rf - y_test)^2), svm = mean((predict_svm - y_test)^2)) } # time for fitting models <- fitModels(gdata$x, gdata$y) testModels(models, gdata$x_test, gdata$y_test) # lasso lm rf svm # 0.8425946 1.4672156 15.7713529 25.0271363 |
Na wykresie im niższy MSE tym lepiej.
Wykresy pudełkowe podsumowują wyniki całych symulacji. Ponieważ nie wykonaliśmy żadnej selekcji cech, więc regresja liniowa cierpi na zastrzyk szumu. Regularyzacja lasso bardzo tutaj pomaga.
Oczywiście metody takie jak SVM czy RandomForest musiały polec, ponieważ w ,,przyszłości’’ Y przyjmuje wartości X1*5, ale X1 jest już z przedziału 1-2 a nie 0-1.
replicate(100, { gdata <- getData(N=N) models <- fitModels(gdata$x, gdata$y) testModels(models, gdata$x_test, gdata$y_test) }) %>% t() %>% boxplot(main = paste("MSE for", N, "variables")) |
Podobna sytuacja jest dla N=5 zmiennych i N=50 zmiennych. Z tym wyjątkiem, że dla N=5 regresja liniowa jest lepsza niż lasso, nie ma tutaj problemu z dużą liczbą zmiennych nie ma co płacić obciążeniem za regularyzację.
Co z tego wynika?
– SVM i RandomForest pracują ,,w dziedzinie’’. Jeżeli występuje trend liniowy to lepiej go wcześniej usunąć chociażby zwykłą regresją (z pewnością też można lepiej niż tylko regresją).
– Jeżeli zmiennych jest dużo to lepiej wykonać jakiś wybór zmiennych, ewentualnie wybrać metodę, która zrobi to za nas (np. Lasso).
– Prognozowanie przyszłości jest znacznie trudniejsze niż przeszłości 😉
Wpisy z kategorii Duże i złożone powstają przy współpracy z firmą CodiLime.
Ciekawy post i dość praktyczny. Sam miałem bardzo konkretne analizy, w których ostatecznie użyłem regresji liniowej zamiast Random Forest, z podobnych powodów. Powinienem był użyć LASSO, ale wtedy jeszcze nie wiedziałem jaką ma przewagę.
Przy czym o ile warto pamiętać, że RF gubi zależność liniową (a raczej – przybliża ją „źle”, bo za pomocą schodków), to w tym (i podobnych) problemach kluczowy jest overfitting (rozumiany jako różnica błędów na danych testowych i treningowych). Rzeczy typu RF świetnie dopasowują się do danych treningowych, ale niekoniecznie przekłada się to na dane testowe. Regresja liniowa ma znacznie mniejszą taką różnicę.
Można też na to patrzeć jak na same parametry – ogólnie regresja ma ich znacznie mniej niż przyzwoity Random Forest – stąd dla małej ilości danych (jak na liczbę kolumn) nic dziwnego, że łatwo dostać dopasowanie do _konkretnych_ danych raczej niż do rozkładu z którego pochodzi.
Pisaliśmy już o tym maile, ale powtórzyć nie zaszkodzi bo i temat ciekawy (nawet bez 'dość’).
RF używa OOB i jakoś sobie radzi z przeuczeniem (zazwyczaj).
Regresja liniowa, szczególnie bez regularyzacji i selekcji na zmienne przeucza się tragicznie (może nie tak tragicznie jak NN czy gołe drzewa).
Ale nawet tragicznie przeuczona regresja liniowa radzi sobie lepiej niż RF dlatego, że obserwowane zjawisko ma w sobie trend w czasie a my tego trendu nie uwzględniliśmy.
Jaka jest pointa moim zdaniem?
Budując warsztat nie wystarczy algorytmy tagować 'przeuczające się’, 'wielowymiarowe’, 'odporne’. Ważne jest by uwzględnić naturę zjawiska i cel jaki ma zrealizować nasz model (opis rzeczywistości / predykcja / aproksymacja).
Niektóre rzeczy z maila są powtórzone na zasadzie „by było publicznie”.
Różne algorytmy mają swoje silne i słabe punkty, które też uwydatniają się przy danych (które też mają swoją specyfikę). Choćby przykład z życia – jakaś tam zależność, gdzie o ile wiadomo, że niektórych efektów nie da się odtworzyć liniowo, to jednak regresja liniowa działała najlepiej (z w/w przyczyn).
W kwestii owego przeuczania – podesłałem wykresy z przeuczaniem. (Szkoda, że tu nie mogę tu wrzucić.) Chodzi o to, że ogólnie „tragicznie przeuczona regresja liniowa” jest względnie mało przeuczona (pewnie i w porównaniu z tragicznie niedouczonym RF).
Możesz linkować wykresy lub używać tagu
, powinno działać.
Co do ,,tragicznie przeuczonej”, odnosi się to do estymacji wszystkich współczynników w sytuacji gdy zdecydowana większość nie ma nic do rzeczy. Bez żadnej walidacji. Można by oczywiście jeszcze bardziej przeuczyć regresję dodając kolejne wielomiany predyktorów.
Kluczowe w problemie jest jednak na jakim zbiorze testowym testować. Jak widać testowanie na podpróbkach tego samego zbioru (vide OOB) nie sprawdza się w tego typu problemach (nawet gdyby je ważyć). Oczywiście mając model symulacyjny łatwiej odpowiedzieć na pytanie gdzie testować, w rzeczywistości jest trudniej.
Obrazki błędów na danych testowych vs treningowych tu:
http://i.imgur.com/ONZmq5V.png (N=5) i http://i.imgur.com/CFm189m.png (N=50).
@Piotr, ciekawie byłoby zobaczyć jak wyglądają trajektorie tych błędów ale na innym wykresie.
Na osi OX przesunięcie [od 0 teraz training set do 1 teraz test set] a na osi OY MSE.
@smarterpoland Tj. linie czy jakaś interpolacja?
a może geom_point() + geom_smooth() ?
Nie wiem czy do końca rozumiem o co Ci chodzi; może o coś takiego:
http://i.imgur.com/oEs26Qs.png
Dokładnie, wygląda fajnie, a czy możesz na osi OX zrobić symulacje z gęstym krokiem, co 0.1 lu 0.01
ciekaw jestem jak wygladaja te profile błędu i gdzie zaczynaja sie problemy
Jednak pomyliłem train/test w wykresie, teraz lepiej:
http://i.imgur.com/gBKzFA2.png
Może na maila (BTW: przypominam się z wątkiem o USOSie – zależy mi by złożyć owo podanie na dnaich), bo _nie rozumiem_ co tu ma znaczyć interpolacja pomiędzy treningiem a testem. Co najwyżej może być różnego podzbioru na dane treningowe i wtedy ocenianie na testowych lub całości.
różnica o której pisałem we wpisie dotyczy sytuacji w której przesuwa się dziedzinę dla zbioru testowego.
przedstawione były przykłady dla 0-ego przesunięcia i przesunięcia o 1, ciekawie byłoby zobaczyć wyniki dla innych przesunięć
stąd pomysł by sprawdzać przesunięcia o 0.1, 0.2 itp
co do USOSa, to nie wiem jak mogę tutaj pomóc. Napisz mi jeżeli masz jakąś sugestię, będę jutro rano w DELab, możemy się nawet spotkać na miejscu
Dalej nie rozumiem o co chodzi z z przesunięciem. Bo jeśli chodzi o wzięcie p części zbioru treningowego i (1-p) części zbioru testowego, to przy liczeniu wariancji przejście będzie liniowe i tyle.
Teraz nie jestem w Wawie, będę od pt. USOS – tylko tyle, czy ktoś nie robił dokładnie tego samego, ew. polecasz mi rzucić okiem na konkretne prace magisterskie czy co.
DELab – powodzenia. Z ludzi technicznych w części naukowej to polecam zagadać do Łukasza Jonaka.
W temacie USOSa, co było robione najłatwiej sprawdzić w APD http://apd.uw.edu.pl/
Z moich dyplomantów pamiętam cztery bardzo fajne prace magisterskie na tym zbiorze danych
Możesz je znaleźć tutaj: http://biecek.pl/PASIK/index.php/PL/PraceMagisterskie
Prognozowanie przyszłości jest znacznie trudniejsze niż przeszłości 😉
prognozowanie przeszłości ?????