Regularyzacja jest powszechnym tematem w uczeniu maszynowym i statystyce bayesowskiej. W tym rozdziale opiszemy trzy najpopularniejsze regularne modele liniowe w literaturze dotyczącej uczenia maszynowego i przedstawimy je w kontekście zestawu danych PISA. Na końcu dokumentu znajdują się ćwiczenia, które pozwolą przetestować zdobytą wiedzę.
Nie daj się zwieść innym, że regresja grzbietowa to wymyślny algorytm sztucznej inteligencji. Czy znasz regresję liniową? Jeśli tak, to regresja grzbietowa jest po prostu adaptacją regresji liniowej.
Celem regresji liniowej lub zwykłej regresji najmniejszych kwadratów
(OLS) jest zminimalizowanie sumy kwadratów reszt. Innymi słowy, należy
dopasować N linii regresji do danych i zachować tylko tę,
która ma najniższą sumę kwadratów reszt. W prostym żargonie formuły, OLS
próbuje minimalizować to:
\[\begin{equation} RSS = \sum_{k = 1}^n(actual_i - predicted_i)^2 \end{equation}\]
Dla każdej dopasowanej linii regresji należy porównać wartość przewidywaną (\(predicted_i\)) z wartością rzeczywistą (\(actual_i\)), podnieść ją do kwadratu i zsumować. Każda dopasowana linia regresji ma następnie powiązaną resztową sumę kwadratów (RSS), a model liniowy wybiera linię o najniższym RSS.
Uwaga: Naukowcy społeczni są zaznajomieni z RSS i nazywają go po prostu jego nazwą. Należy jednak pamiętać, że w żargonie uczenia maszynowego RSS należy do ogólnej rodziny zwanej funkcjami strat. Funkcje strat to wskaźniki, które oceniają dopasowanie modelu i jest ich wiele (takich jak AIC, BIC lub R2).
Regresja grzbietowa wykorzystuje poprzednią funkcję straty RSS i dodaje jeden element:
\[\begin{equation} RSS + \lambda \sum_{k = 1}^n \beta^2_j \end{equation}\]
Termin po prawej stronie nazywany jest karą za kurczenie się, ponieważ wymusza on zbliżenie każdego współczynnika \(\beta_j\) do zera poprzez podniesienie go do kwadratu. Część dotycząca kurczenia się jest jaśniejsza, gdy pomyślimy o tym określeniu jako wymuszającym, aby każdy współczynnik był tak mały, jak to możliwe, bez uszczerbku dla resztkowej sumy kwadratów (RSS). Innymi słowy, chcemy najmniejszych współczynników, które nie wpływają na dopasowanie linii (RSS).
Intuicyjnym przykładem jest myślenie o RSS i \(\sum_{k = 1}^n \beta^2_j\) jako o dwóch oddzielnych rzeczach. RSS szacuje, jak model pasuje do danych, a \(\sum_{k = 1}^n \beta^2_j\) ogranicza stopień nadmiernego dopasowania do danych. Wreszcie, \(\lambda\) pomiędzy tymi dwoma terminami (zwana lambda) może być interpretowana jako „waga”. Im wyższa lambda, tym większa waga zostanie przypisana terminowi kurczenia się równania. Jeśli \(\lambda\) wynosi 0, to pomnożenie 0 przez \(\sum_{k = 1}^n \beta^2_j\) zawsze zwróci zero, zmuszając nasze poprzednie równanie do zredukowania go do pojedynczego wyrażenia \(RSS\).
Dlaczego istnieje potrzeba „ograniczenia” tego, jak dobrze model pasuje do danych? Ponieważ my, naukowcy społeczni i naukowcy zajmujący się danymi, bardzo często nadmiernie dopasowujemy dane. Poniższy wykres przedstawia symulację z Simon Jackson, w której widzimy, że podczas testowania na zestawie treningowym, OLS i Ridge mają tendencję do nadmiernego dopasowania danych. Jednak podczas testowania na danych testowych regresja grzbietowa ma niższy błąd poza próbą, ponieważ $ R2 $ jest wyższy dla modeli z różnymi obserwacjami.
Siła regresji grzbietowej wynika z faktu, że kompromisowo dopasowuje ona dane treningowe naprawdę dobrze w celu poprawy uogólnienia. Innymi słowy, zwiększamy bias (ponieważ zmuszamy współczynniki do bycia mniejszymi) w zamian za niższą zmienność (dzięki czemu nasze przewidywania są bardziej odporne). Innymi słowy, cała istota regresji grzbietowej polega na karaniu bardzo dużych współczynników w celu lepszej generalizacji na nowych danych.
Mając na uwadze tę intuicję, należy pamiętać o jednej ważnej rzeczy: predyktory regresji grzbietowej muszą być znormalizowane. Dlaczego tak się dzieje? Ponieważ ze względu na skalę predyktora jego współczynnik może być bardziej karany niż inne predyktory. Załóżmy, że masz dochód konkretnej osoby (mierzony w tysiącach na miesiąc) i czas spędzony z rodziną (mierzony w sekundach) i próbujesz przewidzieć szczęście. Wzrost wynagrodzenia o jedną jednostkę może być karany znacznie bardziej niż wzrost czasu spędzanego z rodziną o jedną jednostkę tylko dlatego, że wzrost wynagrodzenia o jedną jednostkę może być znacznie większy ze względu na jego metrykę.
W R można dopasować regresję grzbietową za pomocą
tidymodels i tidyflow. Załadujmy pakiety, z
którymi będziemy pracować i wczytajmy dane:
library(tidymodels)
library(tidyflow)
data_link <- "https://raw.githubusercontent.com/cimentadaj/ml_socsci/master/data/pisa_us_2018.csv"
pisa <- read.csv(data_link)
Skonstruujemy nasz tidyflow krok po kroku. Zaczynamy od
danych, a następnie oddzielamy dane treningowe i testowe. Całe nasze
modelowanie zostanie przeprowadzone na danych treningowych, a dane
testowe zostaną zapisane na później (dane testowe należy całkowicie
zignorować, dopóki nie uzyskasz ostatecznego dostrojonego modelu).
Drugim krokiem jest określenie zmiennych w modelu i skalowanie
wszystkich z nich, jak już wyjaśniłem, chcemy znormalizować wszystkie
zmienne tak, aby żadna zmienna nie była bardziej karana niż inne ze
względu na ich metrykę.
# Określ wszystkie zmienne i skalę
rcp <-
# Zdefiniuj zmienną zależną (math_score) i zmienne niezależne
~ recipe(math_score ~ MISCED + FISCED + HISEI + REPEAT + IMMIG + DURECEC + BSMJ, data = .) %>%
# Skaluj wszystkie predyktory (już wie, że to zmienne niezależne)
step_scale(all_predictors())
tflow <-
tidyflow(seed = 231141) %>%
plug_data(pisa) %>%
plug_split(initial_split, prop = .7) %>%
# Dodaj przepis ze wszystkimi zmiennymi i skalą
plug_recipe(rcp)
tflow
## ══ Tidyflow ════════════════════════════════════════════════════════════════════
## Data: 4.84K rows x 501 columns
## Split: initial_split w/ prop = ~0.7
## Recipe: available
## Resample: None
## Grid: None
## Model: None
Argument prop kontroluje część próbki, która znajdzie
się w danych treningowych. Tutaj określamy go na .7, 70%
danych. Trzecim krokiem jest określenie parametrów
tuningu. Regresja grzbietowa ma parametr o nazwie
penalty, który musi być ustawiony przez nas.
penalty jest terminem „wagi” w równaniu regresji
grzbietowej, który kontroluje, jaką wagę chcemy nadać „karze za
kurczenie się” (jest to \(\lambda\) z
równania). Jeśli ta kara jest ustawiona na 0, oznacza to, że
nie przywiązujemy wagi do terminu kary i otrzymamy taki
sam wynik jak w przypadku OLS. Spróbujmy tego:
############################# Regresja grzbietowa ################################
###############################################################################
regularized_reg <-
set_engine(
# mix określa typ regresji ujemnej: 0 oznacza regresję grzbietową
linear_reg(penalty = 0, mixture = 0),
"glmnet"
)
model1 <-
tflow %>%
plug_model(regularized_reg) %>%
fit()
# Pobierz współczynniki grzbietu
mod <- model1 %>% pull_tflow_fit() %>% .[["fit"]]
ridge_coef <- predict(mod, s = 0, type = "coefficients")
############################# Model liniowy ####################################
###############################################################################
model2 <-
tflow %>%
plug_model(set_engine(linear_reg(), "lm")) %>%
fit()
lm_coef <- model2 %>% pull_tflow_fit() %>% .[["fit"]] %>% coef()
############################# Porównanie modeli #################################
###############################################################################
comparison <-
data.frame(coefs = names(lm_coef),
`Linear coefficients` = unname(round(lm_coef, 2)),
`Ridge coefficients` = round(as.vector(ridge_coef), 2))
knitr::kable(comparison)
| coefs | Linear.coefficients | Ridge.coefficients |
|---|---|---|
| (Intercept) | 334.29 | 336.41 |
| MISCED | 3.39 | 3.65 |
| FISCED | 11.59 | 11.28 |
| HISEI | 16.14 | 15.76 |
| REPEAT | -21.22 | -20.67 |
| IMMIG | 4.99 | 4.82 |
| DURECEC | -0.28 | -0.23 |
| BSMJ | 11.19 | 10.97 |
Pochodząc z nauk społecznych, może wydawać się sprzeczne z intuicją,
że badacz musi określić parametry dostrajania modelu. W tradycyjnych
statystykach nauk społecznych modele zwykle szacują podobne wartości
wewnętrznie, a użytkownik nie musi o nich myśleć. Istnieją jednak już
zaimplementowane strategie eksploracji kombinacji wielu możliwych
wartości. W naszym poprzednim przykładzie musimy dodać
tune() do argumentu penalty i dodać siatkę dla
modelu, aby wyszukać najlepszy:
# Tutaj dodajemy walidację krzyżową i siatkę
tflow <-
tflow %>%
# walidacja krzyżową
plug_resample(vfold_cv, v = 5) %>%
# Grid
plug_grid(grid_regular)
regularized_reg <- update(regularized_reg, penalty = tune())
res <-
tflow %>%
# Zaktualizuj model, aby określić, że `penalty` zostanie dostrojone
plug_model(regularized_reg) %>%
fit()
final_ridge <- complete_tflow(res, metric = "rmse")
final_ridge %>%
pull_tflow_fit() %>%
.[["fit"]] %>%
plot(xvar = "lambda", label = TRUE)
Tutaj możemy zobaczyć, jak na nasze współczynniki wpływa zwiększenie
wagi parametru penalty. Każda z tych linii to współczynniki
dla zmiennych. Oś „x” zawiera wartości kar i możemy zobaczyć, jak wraz
ze wzrostem kary, wielkość współczynników zmniejsza się do wartości
bliskiej zeru. Przy logarytmie penalty około 8 prawie
wszystkie współczynniki kurczą się bardzo blisko zera. Ten wykres jest
tylko ćwiczeniem, aby zrozumieć, jak działa regresja grzbietowa. Innymi
słowy, możemy automatycznie określić najlepszą lambdę:
best_tune <-
res %>%
pull_tflow_fit_tuning() %>%
select_best(metric = "rmse")
best_tune
## # A tibble: 1 × 2
## penalty .config
## <dbl> <chr>
## 1 0.0000000001 Preprocessor1_Model1
Nie ma jednak potrzeby obliczania tego, ponieważ
complete_tflow oblicza to za Ciebie (jak widać w powyższym
fragmencie kodu, complete_tflow wyodrębnia to automatycznie
i dopasowuje najlepszy model). Możemy obliczyć \(RMSE\) danych treningowych z najlepszego
modelu i porównać go z przewidywaniami na danych testowych:
train_rmse_ridge <-
final_ridge %>%
predict_training() %>%
rmse(math_score, .pred)
holdout_ridge <-
final_ridge %>%
predict_testing() %>%
rmse(math_score, .pred)
train_rmse_ridge$type <- "training"
holdout_ridge$type <- "testing"
ridge <- as.data.frame(rbind(train_rmse_ridge, holdout_ridge))
ridge$model <- "ridge"
ridge
## .metric .estimator .estimate type model
## 1 rmse standard 77.61301 training ridge
## 2 rmse standard 75.97340 testing ridge
Błąd testowania (RMSE) jest wyższy niż błąd treningu, zgodnie z oczekiwaniami, ponieważ zestaw treningowy prawie zawsze lepiej zapamiętuje dane do treningu.
Regularyzacja Lasso jest bardzo podobna do regularyzacji grzbietowej, w której zmienia się tylko jedna rzecz: termin kary. Zamiast podnosić współczynniki do kwadratu, regularizacja lasso przyjmuje wartość bezwzględną współczynnika.
\[\begin{equation} RSS + \lambda \sum_{k = 1}^n |\beta_j| \end{equation}\]
Chociaż może to nie być oczywiste, reguralizacja lasso ma ważną różnicę: może wymusić, aby współczynnik wynosił dokładnie zero. Oznacza to, że lasso dokonuje selekcji zmiennych, które mają duże współczynniki, jednocześnie nie naruszając RSS modelu. Problem z regresją grzbietową polega na tym, że wraz ze wzrostem liczby zmiennych błąd uczenia prawie zawsze się poprawia, ale błąd testowania nie.
Na przykład, jeśli zdefiniujemy ten sam model z góry za pomocą lasso, zobaczysz, że wymusza on współczynniki dokładnie zerowe, jeśli nie dodają nic w stosunku do RSS modelu. Oznacza to, że zmienne, które nie dodają nic do modelu, zostaną wykluczone, chyba że dodadzą moc wyjaśniającą, która zrekompensuje wielkość ich współczynnika. Oto ten sam przykład lasso:
regularized_reg <- update(regularized_reg, mixture = 1)
res <-
tflow %>%
plug_model(regularized_reg) %>%
fit()
final_lasso <- complete_tflow(res, metric = "rmse")
final_lasso %>%
pull_tflow_fit() %>%
.[["fit"]] %>%
plot(xvar = "lambda", label = TRUE)
W przeciwieństwie do regresji grzbietowej, w której współczynniki są zmuszone być bliskie zeru, kara lasso faktycznie zmusza niektóre współczynniki do bycia zerowymi. Ta właściwość oznacza, że lasso dokonuje selekcji zmiennych o wyższych współczynnikach i eliminuje te, które nie mają silnego związku. Lasso jest zwykle lepsze w interpretacji modelu, ponieważ usuwa zbędne zmienne, podczas gdy ridge może być przydatny, jeśli chcesz zachować pewną liczbę zmiennych w modelu, mimo że są one słabymi predyktorami (na przykład jako kontrole).
Aby sprawdzić ostateczny model i jego błąd, możemy powtórzyć powyższy kod i dostosować go do lasso:
train_rmse_lasso <-
final_lasso %>%
predict_training() %>%
rmse(math_score, .pred)
holdout_lasso <-
final_lasso %>%
predict_testing() %>%
rmse(math_score, .pred)
train_rmse_lasso$type <- "training"
holdout_lasso$type <- "testing"
lasso <- as.data.frame(rbind(train_rmse_lasso, holdout_lasso))
lasso$model <- "lasso"
lasso
## .metric .estimator .estimate type model
## 1 rmse standard 77.63741 training lasso
## 2 rmse standard 76.02502 testing lasso
Póki co możemy sprawdzić, który model radzi sobie lepiej:
model_comparison <- rbind(ridge, lasso)
model_comparison
## .metric .estimator .estimate type model
## 1 rmse standard 77.61301 training ridge
## 2 rmse standard 75.97340 testing ridge
## 3 rmse standard 77.63741 training lasso
## 4 rmse standard 76.02502 testing lasso
Obecnie regresja grzbietowa ma bardzo niewielką przewagę nad lasso, ale różnica jest prawdopodobnie w granicach błędu. W zależności od celu, warto wybrać jeden z tych modeli. Na przykład, jeśli nasze modele zawierają wiele zmiennych, lasso może być bardziej interpretowalne, ponieważ zmniejsza liczbę zmiennych. Jeśli jednak istnieją powody, by sądzić, że utrzymanie wszystkich zmiennych w modelu jest ważne, wówczas przewagę zapewnia ridge.
Jeśli znasz ridge i lasso, to regularyzacja elastyczną siecią jest logicznym krokiem. Elastic Net (nazwa brzmi fantazyjnie, ale jest to również adaptacja OLS) łączy obie kary w jedno równanie.
Tutaj definiujemy naszą karę grzbietową:
\[ridge = \lambda \sum_{k = 1}^n \beta_j^2\]
I tutaj definiujemy naszą karę lasso:
\[lasso = \lambda \sum_{k = 1}^n |\beta_j|\]
Regularyzacja elastycznej sieci polega na dodaniu tych dwóch kar w porównaniu do RSS:
\[RSS + lasso + ridge\]
Myślę, że najlepszym wyjaśnieniem dla elastycznej regularyzacji sieci jest:
Chociaż modele lasso dokonują selekcji cech, gdy dwie silnie skorelowane cechy są popychane w kierunku zera, jedna z nich może zostać całkowicie zepchnięta do zera, podczas gdy druga pozostaje w modelu. Co więcej, proces wchodzenia i wychodzenia jednej cechy z modelu nie jest zbyt systematyczny. Z kolei kara regresji grzbietowej jest nieco bardziej skuteczna w systematycznym radzeniu sobie ze skorelowanymi cechami. W związku z tym zaletą kary elastycznej siatki jest to, że umożliwia ona skuteczną regularyzację za pomocą kary regresji grzbietowej z charakterystyką selekcji cech kary lasso.
Zasadniczo masz teraz dwa parametry strojenia. W siatce wartości,
zamiast określania mixture o wartości 0
(ridge) lub 1 (lasso), tidyflow przesunie się
przez kilka wartości mixture od 0 do 1 i porówna je z
kilkoma wartościami lambda. Jest to formalnie nazywane
grid search.
Możemy powtórzyć ten sam kod co powyżej:
regularized_reg <- update(regularized_reg, mixture = tune())
res <-
tflow %>%
plug_model(regularized_reg) %>%
fit()
final_elnet <- complete_tflow(res, metric = "rmse")
train_rmse_elnet <-
final_elnet %>%
predict_training() %>%
rmse(math_score, .pred)
holdout_elnet <-
final_elnet %>%
predict_testing() %>%
rmse(math_score, .pred)
train_rmse_elnet$type <- "training"
holdout_elnet$type <- "testing"
elnet <- as.data.frame(rbind(train_rmse_elnet, holdout_elnet))
elnet$model <- "elnet"
elnet
## .metric .estimator .estimate type model
## 1 rmse standard 77.61860 training elnet
## 2 rmse standard 75.98468 testing elnet
RMSE elastycznej siatki jest nieco niższy niż grzbietu i lasso, ale również prawdopodobnie mieści się w marginesie błędu. Porównajmy to wizualnie:
model_comparison <- rbind(model_comparison, elnet)
model_comparison %>%
ggplot(aes(model, .estimate, color = type, group = type)) +
geom_point(position = "dodge") +
geom_line() +
scale_y_continuous(name = "RMSE") +
scale_x_discrete(name = "Models") +
theme_minimal()
Fragile Families Challenge to badanie, którego celem było przewidzenie szeregu wskaźników dzieci w wieku 15 lat wyłącznie na podstawie danych w wieku od 0 do 9 lat. W ramach tego wyzwania główni badacze chcieli sprawdzić, czy umiejętności takie jak zdolności poznawcze i pozapoznawcze zostały prawidłowo przewidziane. Mając to na uwadze, byli zainteresowani śledzeniem dzieci, które przekroczyły „przewidywania”: tych dzieci, które przekroczyły przewidywania modelu, na przykład biorąc pod uwagę ich warunki początkowe.
Korzystając z podobnie skonstruowanego proxy niekognitywnego, stworzyłem indeks niekognitywny przy użyciu PISA 2018 dla Stanów Zjednoczonych, który jest średnią z pytań:
Skala indeksu wynosi od 1 do 4, gdzie w 4 student zdecydowanie się zgadza, a 1 oznacza, że całkowicie się nie zgadza. Innymi słowy, wskaźnik ten pokazuje, że im wyższa wartość, tym wyższe umiejętności pozapoznawcze. Możesz sprawdzić pełną książkę kodów PISA [tutaj] (https://docs.google.com/spreadsheets/d/12--3vD737rcu6olviKutRLEiyKNZ2bynXcJ4CpwtNsQ/edit?usp=sharing).
W tej serii ćwiczeń będziesz musiał(a) wypróbować różne modele, które przewidują ten wskaźnik umiejętności pozapoznawczych, przeprowadzić wyszukiwanie siatki dla trzech modeli i porównać przewidywania trzech modeli.
Najpierw zapoznaj się z danymi za pomocą:
library(tidymodels)
library(tidyflow)
data_link <- "https://raw.githubusercontent.com/cimentadaj/ml_socsci/master/data/pisa_us_2018.csv"
pisa <- read.csv(data_link)
tidyflow z podziałem {-#ex1}.pisainitial_split.Pamiętaj, aby ustawić seed na 2341, aby każdy mógł
porównać swoje wyniki.
tflow <-
pisa %>%
tidyflow(seed = 2341) %>%
plug_split(initial_split)
tflow
Podłącz formułę (podpowiedź, spójrz na
?plug_formula) i użyj tylu zmiennych, ile chcesz (możesz
ponownie użyć poprzednich zmiennych z przykładów lub wybrać je
wszystkie). Formuła typu noncogn ~ . spowoduje regresję
noncogn na wszystkich zmiennych.
Podłącz regresję grzbietową z penalty ustawionym na
0.001 (wskazówka: pamiętaj, aby ustawić
mixture na wartość odpowiadającą regresji
grzbietowej).
Dopasowanie modelu grzbietowego (za pomocą
fit)
Prognozuj na danych treningowych za pomocą
predict_training i zbadaj \(R^2\) (rsq) i \(RMSE\) (rmse).
ridge_mod <- set_engine(linear_reg(penalty = 0.001, mixture = 0), "glmnet")
tflow <-
tflow %>%
plug_formula(noncogn ~ .) %>%
plug_model(ridge_mod)
m1 <- fit(tflow)
m1_rsq <- predict_training(m1) %>% rsq(noncogn, .pred)
m1_rmse <- predict_training(m1) %>% rmse(noncogn, .pred)
Usunąć formułę z tidyflow za pomocą
drop_formula.
Dodaj recepturę z tą samą formułą, ale zawierającą
step_scale dla wszystkich predyktorów.
Ponownie uruchom model i wyodrębnij \(R^2\) i \(RMSE\).
Jak zmieniły się \(R^2\) i \(RMSE\)? Czy zmiana miała jakiś wpływ?
rcp <-
~ recipe(noncogn ~ ., data = .) %>%
step_scale(all_predictors())
tflow <-
tflow %>%
drop_formula() %>%
plug_recipe(rcp)
m2 <- fit(tflow)
m2_rsq <- predict_training(m2) %>% rsq(noncogn, .pred)
m2_rmse <- predict_training(m2) %>% rmse(noncogn, .pred)
penalty {-#ex4}.vfold_cv)grid_regular) i określ
levels = 10. Spowoduje to utworzenie siatki strojenia
składającej się z 10 wartościpenalty, aby był
tunedfit)pull_tflow_fit_tuning) i
wizualizuj autoplot.Czy istnieje wzorzec poprawy/zmniejszenia metryk dopasowania w
odniesieniu do penalty?
ridge_mod <- update(ridge_mod, penalty = tune())
tflow <-
tflow %>%
replace_model(ridge_mod) %>%
plug_resample(vfold_cv) %>%
plug_grid(grid_regular, levels = 10)
m3 <- fit(tflow)
m3 %>%
pull_tflow_fit_tuning() %>%
autoplot()
1 (to określa, że
chcemy lasso).fit)pull_tflow_fit_tuning)
i wizualizacja autoplot.Który model działa lepiej? Ridge czy Lasso? Czy możesz skomentować wzór kary między ridge i lasso?
lasso_mod <- update(ridge_mod, mixture = 1)
m4 <-
tflow %>%
replace_model(lasso_mod) %>%
fit()
m4 %>%
pull_tflow_fit_tuning() %>%
autoplot()
tuned mixturetidyflow modelem elastycznej
siatki.fit)pull_tflow_fit_tuning) i
wizualizuj autoplot.elnet_mod <- update(lasso_mod, mixture = tune())
m5 <-
tflow %>%
replace_model(elnet_mod) %>%
fit()
m5 %>%
pull_tflow_fit_tuning() %>%
autoplot()
# Dodatkowy wykres z błędem standardowym
library(tidyr)
m5 %>%
pull_tflow_fit_tuning() %>%
collect_metrics() %>%
pivot_longer(penalty:mixture) %>%
mutate(low = mean - (std_err * 2),
high = mean + (std_err * 2)) %>%
ggplot(aes(value, mean)) +
geom_point() +
geom_errorbar(aes(ymin = low, ymax = high)) +
facet_grid(.metric ~ name)
complete_tflow. Pamiętaj, aby
ustawić metric!complete_tflow) do
predict_training i predict_testing na każdym z
nichrmse trzech modeli zarówno na treningu, jak i na
testach.# Ponieważ będziemy powtarzać ten sam proces wiele razy
# napiszmy funkcję do przewidywania na podstawie treningu/testu
# i połączmy je. Ta funkcja zaakceptuje pojedynczy
# model i utworzy ramkę danych z błędem RMSE dla
# treningu i testów. W ten sposób możemy ponownie wykorzystać kod
# bez konieczności kopiowania wszystkiego wiele razy
calculate_err <- function(final_model, type_model = NULL) {
final_model <- complete_tflow(final_model, metric = "rmse")
err_train <-
final_model %>%
predict_training() %>%
rmse(noncogn, .pred)
err_test <-
final_model %>%
predict_testing() %>%
rmse(noncogn, .pred)
err_train$type <- "train"
err_test$type <- "test"
res <- as.data.frame(rbind(err_train, err_test))
res$model <- type_model
res
}
final_res <-
rbind(
calculate_err(m3, "ridge"),
calculate_err(m4, "lasso"),
calculate_err(m5, "elnet")
)
final_res %>%
ggplot(aes(model, .estimate, color = type)) +
geom_point() +
theme_minimal()
## BONUS
## Dopasuj regresję liniową i porównaj cztery modele
## Jaki model jest najlepszy, biorąc pod uwagę zarówno dokładność, jak i prostotę?