PoweR: Modele uczenia maszynowego

Mateusz Krzyziński

3/20/23

Wstęp

Zanim przejdziemy do meritum…

Set up

Instalacja pakietów, z których będziemy korzystać. Lepiej to zrobić przed zajęciami :)

install.packages('DALEX')
install.packages('partykit')
install.packages('randomForest')
install.packages('gbm')
install.packages('e1071')

Czemu paczek jest tak dużo?

  • w R wiele modeli ma swoje oddzielne implementacje w osobnych bibliotekach

  • nawet meta-pakiety wykorzystują de facto pod spodem te mniejsze paczki

Takie rozdrobnienie ma też swój plus – pakiety są bardziej dopracowane, mają więcej funkcjonalności i parametrów.

Ogrom dostępnych bibliotek można zauważyć przeglądając CRAN Task View: Machine Learning & Statistical Learning.

Program

GŁÓWNY CEL: Zapoznanie z …

  • podziałem (taksonomią) uczenia maszynowego
    - czyli czego i po co uczymy maszyny?
  • podstawowymi modelami uczenia maszynowego
    - czyli jak je uczymy?

Na jakich modelach się skupimy?

  • regresja liniowa,

  • regresja logistyczna,

  • drzewa decyzyjne,

  • lasy losowe,

  • modele boostingowe,

  • metoda k najbliższych sąsiadów.

Taksonomia uczenia maszynowego

flowchart TB
  A((UCZENIE MASZYNOWE)) -- mamy dane i odpowiedzi --> B(NADZOROWANE)
  A -- nie mamy danych, mamy środowisko --> D(ZE WZMOCNIENIEM)
  A -- mamy dane, nie mamy odpowiedzi --> C(NIENADZOROWANE)
  B -- przewidujemy liczbę --> E([regresja])
  B -- przewidujemy kategorię --> F([klasyfikacja])
  C -- dzielimy na grupy --> G([klasteryzacja])
  C -- szukamy outlierów --> H([wykrywanie anomalii])
  

Taksonomia uczenia maszynowego

flowchart TB
  A((UCZENIE MASZYNOWE)) -- mamy dane i odpowiedzi --> B(NADZOROWANE)
  A -- mamy dane, nie mamy odpowiedzi --> C(NIENADZOROWANE)
  A -- nie mamy danych, mamy środowisko --> D(ZE WZMOCNIENIEM)
  subgraph  
     B -- przewidujemy liczbę --> E([regresja])
     B -- przewidujemy kategorię --> F([klasyfikacja])
  end
  C -- dzielimy na grupy --> G([klasteryzacja])
  C -- szukamy outlierów --> H([wykrywanie anomalii])
  

Uczenie nadzorowane

Co mamy?

  • \(X\) – dane
    (zmienne objaśniające/predyktory/zmienne niezależne)

    • w większości przypadków chcemy, żeby \(X \in \mathbb{R}_{n\times p}\) (\(n\) obserwacji \(p\) zmiennych) – właśnie po to jest nam potrzebny feature engineering (poprzednie zajęcia)
  • \(Y\) – odpowiedzi
    (zmienna objaśniana/target/zmienna zależna)

    • dla zadania regresji \(Y \in \mathbb{R}\) (odpowiedź to liczba)

    • dla zadania klasyfikacji \(Y \in \{1, 2, \ldots, g\}\) (odpowiedź to etykieta, kategoria)

Co chcemy osiągnąć?

  • \(F\) – model, który umie przewidywać \(Y\) na podstawie \(X\)
  • musi się tego nauczyć na podstawie zgromadzonych danych
    (poprzez trening/fitowanie/dopasowanie)

Uczenie nadzorowane - przykłady problemów

Regresja

  • predykcja ceny mieszkania na podstawie jego cech (np. metrażu, położenia, jakości wykończenia, roku wybudowania),
  • predykcja ilości sprzedaży danego produktu w zależności od jego ceny, promocji i innych czynników marketingowych,
  • predykcja temperatury w danym miejscu i czasie na podstawie danych meteorologicznych,
  • predykcja czasu, który użytkownik spędzi na danej stronie internetowej w zależności od liczby kliknięć i czasu spędzonego na innych stronach,

Klasyfikacja

  • predykcja, czy dany e-mail jest spamem na podstawie jego treści,
  • predykcja, czy danemu klientowi banku należy przyznać wnioskowany kredyt na podstawie historii kredytowej i cech klienta,
  • predykcja, czy na zdjęciu znajduje się pies, czy kot,
  • predykcja, czy dany pacjent na podstawie wyników choruje na określoną chorobę,

Podstawowe modele uczenia maszynowego

Wczytanie zbiorów

  • dla zadania regresji:

    apartments_regr_train <- DALEX::apartments
    apartments_regr_test <- DALEX::apartments_test
  • dla zadania klasyfikacji:

    titanic_dataset <- DALEX::titanic_imputed
    titanic_dataset$survived <- as.factor(titanic_dataset$survived )
    n <- nrow(titanic_dataset)
    set.seed(42)
    train_mask <- sample(n, 0.8*n)
    titanic_class_train <- titanic_dataset[train_mask,]
    titanic_class_test <- titanic_dataset[-train_mask,]
    
    pima_class_train <- MASS::Pima.tr
    pima_class_test <- MASS::Pima.te

Zbiór treningowy a testowy

  • zbiór treningowy – trenowanie (uczenie) modelu

  • zbiór testowy – testowanie jakości modelu na niewidzianych danych (następne zajęcia)

Regresja liniowa

  • Działa dla zadania regresji.

  • Dla \(p=1\) (jednej zmiennej objaśniającej) polega na dopasowaniu prostej (funkcji liniowej):

linreg_model_simple <- lm(m2.price ~ surface, data = apartments_regr_train)
plot(apartments_regr_train$surface, apartments_regr_train$m2.price, pch=16,
     xlab="Powierzchnia [m^2]",
     ylab="Cena za m^2")
abline(linreg_model_simple, col="red", lwd=3)

coef(linreg_model_simple)
(Intercept)     surface 
 4523.13639   -12.10559 
  • Ogólniej: nasz model \(F\) wyraża się jako: \(\hat{Y} = F(X) = X \hat{\beta}\), czyli dla \(i\)-tej obserwacji: \[\hat{y_i} = \hat{\beta_0} + \hat{\beta_1} \cdot x_{i1} + \hat{\beta_2} \cdot x_{i2} + \ldots + \hat{\beta_p} \cdot x_{ip}.\]

  • Na czym polega trening?

    • szukamy współczynników (wag modelu) \(\hat{\beta}\),

    • wybieramy takie \(\hat{\beta}\), które minimalizuje sumę kwadratów błędów predykcji na zbiorze treningowym \(L = \sum_{i=1}^{n} (y_i - \hat{y_i})^2\),

    • przy takiej funkcji straty \(L\) mamy wzór jawny na \(\hat{\beta}\).

  • W praktyce używamy wbudowanej w R funkcji lm() (od linear model):

linreg_model <- lm(m2.price ~ ., data = apartments_regr_train)
summary(linreg_model) # podsumowanie statystyczne

Call:
lm(formula = m2.price ~ ., data = apartments_regr_train)

Residuals:
   Min     1Q Median     3Q    Max 
-247.5 -202.8 -172.8  381.4  469.0 

Coefficients:
                     Estimate Std. Error t value Pr(>|t|)    
(Intercept)         5020.1391   682.8721   7.352 4.11e-13 ***
construction.year     -0.2290     0.3483  -0.657   0.5110    
surface              -10.2378     0.5778 -17.720  < 2e-16 ***
floor                -99.4820     3.0874 -32.222  < 2e-16 ***
no.rooms             -37.7299    15.8440  -2.381   0.0174 *  
districtBielany       17.2144    40.4502   0.426   0.6705    
districtMokotow      918.3802    39.4386  23.286  < 2e-16 ***
districtOchota       926.2540    40.5279  22.855  < 2e-16 ***
districtPraga        -37.1047    40.8930  -0.907   0.3644    
districtSrodmiescie 2080.6110    40.0149  51.996  < 2e-16 ***
districtUrsus         29.9419    39.7249   0.754   0.4512    
districtUrsynow      -18.8651    39.7565  -0.475   0.6352    
districtWola         -16.8912    39.6283  -0.426   0.6700    
districtZoliborz     889.9735    40.4099  22.024  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 281.3 on 986 degrees of freedom
Multiple R-squared:  0.905, Adjusted R-squared:  0.9037 
F-statistic: 722.5 on 13 and 986 DF,  p-value: < 2.2e-16
predictions <- predict(linreg_model, apartments_regr_test[1:10, ])
as.numeric(predictions)
 [1] 4820.009 3292.678 2717.910 2922.751 2974.086 2527.043 3200.487 2539.230
 [9] 2780.212 4529.007
apartments_regr_test[1:10, "m2.price"]
 [1] 4644 3082 2498 2735 2781 2936 3010 2370 2593 4311
  • Jak sprawdzić czy model działa dobrze?
    To temat następnych zajęć.

  • ZALETY:

    • Istnieje wiele statystycznych metod testowania i diagnostyki.

    • Interpretowalność.

    • Łatwość optymalizacji (jawny wzór) i lekkość.

  • WADY:

    • Podatność na obserwacje odstające.
    • Założenie o liniowej zależności pomiędzy zmiennymi objaśniającymi a zmienną odpowiedzi.

Regresja logistyczna

  • “Odpowiednik” regresji liniowej dla zadania klasyfikacji.

  • Dla dwóch klas \(\{0, 1\}\): interesuje nas \(\mathbb{P}(y=1/x) = p_1(x)\) prawdopodobieństwo przynależności danej obserwacji \(x\) do klasy 1 (prawdopodobieństwo “sukcesu”).

  • Dla \(p=1\) (jednej zmiennej objaśniającej):

    logreg_model_simple <- glm(type~glu, data=pima_class_train, family = "binomial")
    plot(pima_class_train$glu, pima_class_train$type == "Yes", pch=16,
         xlab="Stężenie glukozy",
         ylab="Cukrzyca")
    glu_sequence <- seq(min(pima_class_train$glu), max(pima_class_train$glu), 1)
    predictions <- predict(logreg_model_simple, data.frame(glu=glu_sequence), type = "response")
    lines(glu_sequence, predictions, type="l", lwd=3, col="red")

    coef(logreg_model_simple)
    (Intercept)         glu 
    -5.50363574  0.03778372 
  • Zamiast prawdopodobieństwa modelujemy liniowo logarytm szans (p-stwo jest z przedziału [0, 1], a logarytm szans nie).

  • Szansa to stosunek prawdopodobieństwa sukcesu do prawdopodobieństwa porażki: \(odds = \frac{p_1}{1-p_1}\).

  • Nasz model wyraża się jako: \[\log(odds) = \hat{\beta_0} + \hat{\beta_1} \cdot x_{i1} + \hat{\beta_2} \cdot x_{i2} + \ldots + \hat{\beta_p} \cdot x_{ip}.\]

  • Na czym polega trening?

    • szukamy współczynników (wag modelu) \(\hat{\beta}\),

    • wybieramy takie \(\hat{\beta}\), które maksymalizuje funkcję wiarogodności (likelihood), tzn.:

      • dla obserwacji z klasy 1 daje wartości \(p_1(x)\) możliwie bliskie 1,

      • dla obserwacji z klasy 0 daje wartości \(p_1(x)\) możliwie bliskie 0.

  • W praktyce używamy wbudowanej w R funkcji glm() (od generalized linear model):

    logreg_model <- glm(survived~., data=titanic_class_train, family = "binomial")
    summary(logreg_model)
    
    Call:
    glm(formula = survived ~ ., family = "binomial", data = titanic_class_train)
    
    Deviance Residuals: 
        Min       1Q   Median       3Q      Max  
    -2.1893  -0.7140  -0.4812   0.6022   2.6396  
    
    Coefficients:
                           Estimate Std. Error z value Pr(>|z|)    
    (Intercept)            3.158385   0.466352   6.773 1.27e-11 ***
    gendermale            -2.689430   0.173749 -15.479  < 2e-16 ***
    age                   -0.037343   0.005978  -6.246 4.20e-10 ***
    class2nd              -1.011603   0.279881  -3.614 0.000301 ***
    class3rd              -2.061504   0.275707  -7.477 7.59e-14 ***
    classdeck crew         1.350311   0.394180   3.426 0.000613 ***
    classengineering crew -0.846771   0.290912  -2.911 0.003606 ** 
    classrestaurant staff -3.290541   0.774814  -4.247 2.17e-05 ***
    classvictualling crew -0.820075   0.285759  -2.870 0.004107 ** 
    embarkedCherbourg      0.921634   0.315933   2.917 0.003532 ** 
    embarkedQueenstown     0.411062   0.375373   1.095 0.273484    
    embarkedSouthampton    0.302534   0.237490   1.274 0.202706    
    fare                   0.001538   0.002082   0.739 0.460160    
    sibsp                 -0.339313   0.099823  -3.399 0.000676 ***
    parch                 -0.059689   0.105761  -0.564 0.572497    
    ---
    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    
    (Dispersion parameter for binomial family taken to be 1)
    
        Null deviance: 2216.2  on 1764  degrees of freedom
    Residual deviance: 1640.4  on 1750  degrees of freedom
    AIC: 1670.4
    
    Number of Fisher Scoring iterations: 5

    Domyślnie predykowane są log-oddsy. W celu uzyskania prawdopodobieństw należy zmienić parametr type na "response".

    predictions_logodds <- predict(logreg_model, titanic_class_test[1:10, ]) 
    as.numeric(predictions_logodds)
     [1]  0.8128850 -1.0437219  0.5110133  3.1599875 -1.3696115 -0.1041560
     [7] -0.4402464 -1.2328536  0.8056224  0.8816578
    predictions_probs <- predict(logreg_model, titanic_class_test[1:10, ], type="response") 
    as.numeric(predictions_probs)
     [1] 0.6927239 0.2604325 0.6250440 0.9593005 0.2026826 0.4739845 0.3916823
     [8] 0.2256824 0.6911759 0.7071656
    titanic_class_test[1:10, "survived"]
     [1] 1 0 1 0 0 0 0 0 1 1
    Levels: 0 1
  • ZALETY:

    • Istnieje wiele statystycznych metod testowania i diagnostyki.

    • Interpretowalność.

  • WADY:

    • Podatność na obserwacje odstające.
    • Założenie o liniowości.

Drzewo decyzyjne

  • Może być użyte zarówno do problemu regresji, jak i klasyfikacji – często nazywane CART (Classification And Regression Trees).

  • Działanie polega na podziale przestrzeni predyktorów na regiony o różnej wartości zmiennej odpowiedzi (dla klasyfikacji – prawdopodobieństwo przynależności do klasy).

  • Algorytm można opisać krokowo:

    1. Zaczynamy od korzenia drzewa – pojedynczego węzła, w którym mamy cały zbiór danych.

    2. Dla obecnego węzła szukamy odpowiedniego podziału zbioru danych. W tym celu rozważamy każdą zmienną i dla każdej z nich analizujemy:

      1. jeśli jest ciągła: każdy możliwy cutoff (wartość odcięcia),
      2. jeśli jest kategoryczna: każdy możliwy podzbiór poziomów.
        Wybieramy taki podział (zmienną i wartość), która maksymalizuje miarę odseparowania, umożliwia jak najbardziej różnicujący podział danych ze względy na \(Y\).
    3. Sprawdzamy, czy zostało spełnione kryterium stopu, np.

      1. osiągnęliśmy maksymalną głębokość drzewa,
      2. osiągnęliśmy minimalny zysk na czystości węzłów.
        Jeśli warunek stopu jest spełniony – przerywamy.
        W przeciwnym wypadku – dzielimy obecny węzeł na dwa według znalezionego podziału i dla każdego z węzłów-potomków idziemy do kroku 2 (niezależnie).
  • Miary jakości podziału:

    • dla regresji: minimalizujemy błąd średniokwadratowy patrząc na predykcję dla regionów \(R_1\) i \(R_2\):\(MSE = \sum_{i \in R_1} (y_i-\hat{y_{R_1}})^2 + \sum_{i \in R_2} (y_i-\hat{y_{R_2}})^2\)

    • dla klasyfikacji: Gini index, entropia.

  • W praktyce jest wiele różnych pakietów oferujących budowanie drzew decyzyjnych. Tutaj wykorzystamy bibliotekę partykit, która umożliwia tworzenie przejrzystych wizualizacji drzew oraz pozwala na specyfikację wielu parametrów (ctree_control).

    library(partykit)
    class_tree_model <- ctree(survived~., data=titanic_class_train)
    class_tree_model
    
    Model formula:
    survived ~ gender + age + class + embarked + fare + sibsp + parch
    
    Fitted party:
    [1] root
    |   [2] gender in female
    |   |   [3] class in 1st, 2nd, restaurant staff, victualling crew: 1 (n = 206, err = 6.3%)
    |   |   [4] class in 3rd
    |   |   |   [5] embarked in Cherbourg, Queenstown: 1 (n = 71, err = 35.2%)
    |   |   |   [6] embarked in Southampton
    |   |   |   |   [7] fare <= 22: 0 (n = 86, err = 45.3%)
    |   |   |   |   [8] fare > 22: 0 (n = 25, err = 4.0%)
    |   [9] gender in male
    |   |   [10] class in 1st, 2nd, 3rd, engineering crew, restaurant staff, victualling crew
    |   |   |   [11] class in 1st, engineering crew, victualling crew
    |   |   |   |   [12] age <= 32: 0 (n = 373, err = 29.0%)
    |   |   |   |   [13] age > 32: 0 (n = 350, err = 18.0%)
    |   |   |   [14] class in 2nd, 3rd, restaurant staff
    |   |   |   |   [15] age <= 4
    |   |   |   |   |   [16] sibsp <= 2: 1 (n = 17, err = 11.8%)
    |   |   |   |   |   [17] sibsp > 2: 0 (n = 8, err = 12.5%)
    |   |   |   |   [18] age > 4: 0 (n = 577, err = 11.4%)
    |   |   [19] class in deck crew: 1 (n = 52, err = 32.7%)
    
    Number of inner nodes:     9
    Number of terminal nodes: 10
    plot(class_tree_model)

    regr_tree_model <- ctree(m2.price~., 
                             data=apartments_regr_train, 
                             control = ctree_control(maxdepth=4)
                            )
    regr_tree_model
    
    Model formula:
    m2.price ~ construction.year + surface + floor + no.rooms + district
    
    Fitted party:
    [1] root
    |   [2] district in Bemowo, Bielany, Praga, Ursus, Ursynow, Wola
    |   |   [3] surface <= 87
    |   |   |   [4] floor <= 4
    |   |   |   |   [5] surface <= 50: 3911.536 (n = 56, err = 5618743.9)
    |   |   |   |   [6] surface > 50: 3499.829 (n = 76, err = 6474984.8)
    |   |   |   [7] floor > 4
    |   |   |   |   [8] surface <= 48: 3399.257 (n = 74, err = 7342186.1)
    |   |   |   |   [9] surface > 48: 3027.575 (n = 106, err = 10996837.9)
    |   |   [10] surface > 87
    |   |   |   [11] floor <= 6
    |   |   |   |   [12] surface <= 105: 3129.833 (n = 48, err = 5235614.7)
    |   |   |   |   [13] surface > 105: 2709.107 (n = 121, err = 13335733.6)
    |   |   |   [14] floor > 6
    |   |   |   |   [15] surface <= 122: 2485.000 (n = 61, err = 5443088.0)
    |   |   |   |   [16] surface > 122: 2084.224 (n = 58, err = 4742256.1)
    |   [17] district in Mokotow, Ochota, Srodmiescie, Zoliborz
    |   |   [18] district in Mokotow, Ochota, Zoliborz
    |   |   |   [19] surface <= 80
    |   |   |   |   [20] floor <= 4: 4658.787 (n = 47, err = 7109963.9)
    |   |   |   |   [21] floor > 4: 4070.956 (n = 90, err = 9931231.8)
    |   |   |   [22] surface > 80
    |   |   |   |   [23] floor <= 5: 3799.507 (n = 73, err = 11517088.2)
    |   |   |   |   [24] floor > 5: 3311.400 (n = 90, err = 12840189.6)
    |   |   [25] district in Srodmiescie
    |   |   |   [26] surface <= 61
    |   |   |   |   [27] floor <= 2: 6172.000 (n = 11, err = 635246.0)
    |   |   |   |   [28] floor > 2: 5572.241 (n = 29, err = 2472955.3)
    |   |   |   [29] surface > 61
    |   |   |   |   [30] floor <= 8: 4972.178 (n = 45, err = 7138790.6)
    |   |   |   |   [31] floor > 8: 4336.000 (n = 15, err = 2065332.0)
    
    Number of inner nodes:    15
    Number of terminal nodes: 16
    plot(regr_tree_model)

  • Predykcją jest średnia wartość zmiennej odpowiedzi dla obserwacji ze zbioru treningowego, które trafiły do tego samego liścia.

    predict(class_tree_model, titanic_class_test[1:10,])
     5  7 23 24 28 34 38 44 48 50 
     0  0  0  1  0  0  0  0  1  1 
    Levels: 0 1
    predict(class_tree_model, titanic_class_test[1:10,], type="prob")
               0         1
    5  0.5465116 0.4534884
    7  0.8856153 0.1143847
    23 0.7104558 0.2895442
    24 0.0631068 0.9368932
    28 0.8856153 0.1143847
    34 0.9600000 0.0400000
    38 0.9600000 0.0400000
    44 0.8856153 0.1143847
    48 0.0631068 0.9368932
    50 0.0631068 0.9368932
    predict(regr_tree_model, apartments_regr_test[1:10,])
        1001     1002     1003     1004     1005     1006     1007     1008 
    4972.178 3311.400 2485.000 2709.107 3129.833 2485.000 3027.575 2709.107 
        1009     1010 
    3027.575 4070.956 
Decision tree vs logistic regression

Model liniowy vs. drzewo decyzyjne. Źródło: An Introduction to Statistical Learning

  • ZALETY:

    • Interpretowalność.

    • Intuicyjność.

    • Obsługa zmiennych kategorycznych bez konieczności ich kodowania (np. one hot encodingu).

  • WADY:

    • Nienajlepszy performance.
    • Nieodporność na zmiany w danych, overfitting.

Las losowy

  • Podobnie jak drzewo decyzyjne – może być użyty zarówno do problemu regresji, jak i klasyfikacji.

  • Idea: “mądrość tłumu” – połączeniu wielu różnych modeli w jeden poprawi jego własności.

  • Las tworzy się z wielu różnych od siebie drzew decyzyjnych, których predykcje są agregowane (ensembling).

  • Zróżnicowanie drzew wynika z losowości zastosowanej na dwóch poziomach:

    1. trenujemy każde pojedyncze drzewo na nieco innym zbiorze danych (generujemy \(B\) zbiorów treningowych wykorzystując procedurę bootstrapu, czyli losując ze zwracaniem obserwacje z całego, pierwotnego zbioru treningowego),

    2. na każdym poziomie budowanego drzewa rozważamy tylko losowo wybrany podzbiór zmiennych jako kandydatów do podziału węzła.

  • W praktyce są dwa bardzo popularne pakiety oferujące budowanie lasów losowych (ranger i randomForest). Tutaj wykorzystamy bibliotekę randomForest.

    library(randomForest)
    class_rf_model <- randomForest(survived~., data=titanic_class_train)
    class_rf_model
    
    Call:
     randomForest(formula = survived ~ ., data = titanic_class_train) 
                   Type of random forest: classification
                         Number of trees: 500
    No. of variables tried at each split: 2
    
            OOB estimate of  error rate: 19.21%
    Confusion matrix:
         0   1 class.error
    0 1126  72  0.06010017
    1  267 300  0.47089947
    regr_rf_model <- randomForest(m2.price~., data=apartments_regr_train)
    regr_rf_model
    
    Call:
     randomForest(formula = m2.price ~ ., data = apartments_regr_train) 
                   Type of random forest: regression
                         Number of trees: 500
    No. of variables tried at each split: 1
    
              Mean of squared residuals: 79103.29
                        % Var explained: 90.37
  • Predykcja jest dokonywana przez głosowanie pojedynczych drzew.

    • dla klasyfikacji:
    predict(class_rf_model, titanic_class_test[1:10,]) #klasy
     5  7 23 24 28 34 38 44 48 50 
     1  0  1  1  0  0  0  0  1  1 
    Levels: 0 1
    predict(class_rf_model, titanic_class_test[1:10,], type="prob") #prawdopodobieństwa
           0     1
    5  0.344 0.656
    7  0.842 0.158
    23 0.304 0.696
    24 0.270 0.730
    28 0.968 0.032
    34 0.770 0.230
    38 0.958 0.042
    44 0.986 0.014
    48 0.254 0.746
    50 0.054 0.946
    attr(,"class")
    [1] "matrix" "array"  "votes" 
    predict(class_rf_model, titanic_class_test[1:10,], type="vote", norm.votes=FALSE) #liczba głosów
         0   1
    5  172 328
    7  421  79
    23 152 348
    24 135 365
    28 484  16
    34 385 115
    38 479  21
    44 493   7
    48 127 373
    50  27 473
    attr(,"class")
    [1] "matrix" "array"  "votes" 
    • dla regresji:
    predict(regr_rf_model, apartments_regr_test[1:10,])
        1001     1002     1003     1004     1005     1006     1007     1008 
    4201.783 3198.354 2680.807 2718.013 2931.929 3027.829 3330.289 2673.959 
        1009     1010 
    2812.673 4249.530 

Boosting

  • Może być użyty zarówno do problemu regresji, jak i klasyfikacji.

  • Idea: “mądrość tłumu” – połączeniu wielu różnych modeli w jeden poprawi jego własności.

  • Budowanie modelu polega na sekwencyjnym tworzeniu “słabych modeli” (w przypadku wykorzystania drzew decyzyjnych – płytkich drzew).

  • Modele tworzone są po sobie w taki sposób, że każdy kolejny ma na celu redukować błędy poprzedniego. Pierwsze drzewo trenowane jest z wykorzystaniem oryginalnego \(Y\), a każde kolejne trenowane jest już w oparciu o rezydua (błędy) dotychczasowego modelu.

  • W praktyce idea boostingu wykorzystywana jest w wielu różnych frameworkach (np. XGBoost, LightGBM, AdaBoost, Catboost, …), tutaj wykorzystamy natomiast pakiet gbm.

    library(gbm)
    class_gbm_model <- gbm(as.character(survived)~., distribution="bernoulli", data=titanic_class_train)
    class_gbm_model
    gbm(formula = as.character(survived) ~ ., distribution = "bernoulli", 
        data = titanic_class_train)
    A gradient boosted model with bernoulli loss function.
    100 iterations were performed.
    There were 7 predictors of which 7 had non-zero influence.
    regr_gbm_model <- gbm(m2.price~., distribution="gaussian", data=apartments_regr_train)
    regr_gbm_model
    gbm(formula = m2.price ~ ., distribution = "gaussian", data = apartments_regr_train)
    A gradient boosted model with gaussian loss function.
    100 iterations were performed.
    There were 5 predictors of which 5 had non-zero influence.
  • Predykcja jest dokonywana przez agregację predykcji poszczególnych drzew.

    # popularny błąd: predykcje nie działają dla klasyfikatora, gdzie y był factorem
    predict(class_gbm_model, titanic_class_test[1:10,])
     [1]  0.3395122 -0.8562792  1.3129825  3.3230206 -1.5575703  0.5773034
     [7] -0.7025372 -1.2844245  0.7509905  1.3315128
    predict(regr_gbm_model, apartments_regr_test[1:10,]) 
     [1] 4531.277 3150.107 2644.342 2778.567 2988.292 2790.107 3090.705 2524.319
     [9] 2638.503 4262.517

Metoda k najbliższych sąsiadów

  • Może być użyta zarówno do problemu regresji, jak i klasyfikacji.

  • Bardzo prosta idea: dla nowej obserwacji wyszukujemy \(k\) (predefiniowaną liczbę) najbliższych pod względem odległości obserwacji ze zbioru treningowego i wyznaczamy predykcję na ich podstawie:

    • dla klasyfikacji: prawdopodobieństwa klas to frakcja etykiet danej klasy wśród \(k\) znalezionych sąsiadów,

    • dla regresji: średnia z \(Y\) wśród \(k\) znalezionych sąsiadów.

  • Można wykorzystać właściwie dowolną miarę odległości – kluczowe jest skalowanie zmiennych.

  • Wizualizacja działania KNN dla k=3. Źródło: An Introduction to Statistical Learning

  • W praktyce wykorzystamy pakiet e1071.

    library(e1071)
    class_knn_model <- gknn(survived~., data=titanic_class_train, scale=TRUE, k=5)
    class_knn_model$x[1:2,]
         genderfemale gendermale        age class2nd class3rd classdeck crew
    1177            0          1  3.5962996        0        1              0
    1098            0          1 -0.9246944        0        1              0
         classengineering crew classrestaurant staff classvictualling crew
    1177                     0                     0                     0
    1098                     0                     0                     0
         embarkedCherbourg embarkedQueenstown embarkedSouthampton       fare
    1177                 0                  0                   1 -0.2961186
    1098                 1                  0                   0 -0.2986197
              sibsp    parch
    1177 -0.3551151 -0.33145
    1098 -0.3551151 -0.33145
    regr_knn_model <- gknn(m2.price~., data=apartments_regr_train, scale=TRUE, k=5)
    regr_knn_model$x[1:2,]
      construction.year   surface      floor  no.rooms districtBemowo
    1        -0.4576968 -1.599744 -0.9045215 -1.708393              0
    2         1.0520871  1.515784  1.1645326  1.187188              0
      districtBielany districtMokotow districtOchota districtPraga
    1               0               0              0             0
    2               1               0              0             0
      districtSrodmiescie districtUrsus districtUrsynow districtWola
    1                   1             0               0            0
    2                   0             0               0            0
      districtZoliborz
    1                0
    2                0
  • Predykcje:

    predict(class_knn_model, titanic_class_test[1:10,])
     5  7 23 24 28 34 38 44 48 50 
     1  0  1  1  0  0  0  0  1  1 
    Levels: 0 1
    predict(class_knn_model, titanic_class_test[1:10,], type="votes")
       0 1
    5  2 3
    7  3 2
    23 2 3
    24 1 4
    28 5 2
    34 3 2
    38 3 2
    44 5 0
    48 2 3
    50 0 5
    predict(regr_knn_model, apartments_regr_test[1:10,])
      1001   1002   1003   1004   1005   1006   1007   1008   1009   1010 
    4806.2 3101.4 2576.4 2796.8 2915.2 2744.0 3164.2 2470.2 2590.2 4249.6 

Podsumowanie

Polecane materiały

Pytania?