4  Przegląd miar dopasowania modelu

Wszystkie modele są błędne, ale niektóre są przydatne - George E.P. Box

Ocenę jakości dopasowania modelu można dokonywać na różne sposoby:

1 dotyczy to modeli regresyjnych

2 czyli większej niż dwie

W tym rozdziale przedstawimy najpowszechniej stosowane miary dopasowania modelu w podziale na modele regresyjne i klasyfikacyjne. Przy czym w rodzinie modeli klasyfikacyjnych można wyszczególnić podklasę modeli, dla których zmienna wynikowa jest binarna. Modele ze zmienną wynikową binarną stanowią oddzielną klasę w kontekście dopasowania, ponieważ stosuje się wówczas inne miary dopasowania. Co prawda miary te można zastosować również w przypadku zmiennej wynikowej o większej liczbie kategorii2, ale wymaga to wówczas przyjęcia dodatkowych umów w jaki sposób je stosować, a sposoby te nie są jednoznaczne.

4.1 Miary dopasowania modeli regresyjnych

Przegląd zaczniemy od najlepiej znanych miar, a skończymy na rzadziej stosowanych, jak funkcja straty Hubera.

4.1.1 \(R^2\)

Miara stosowana najczęściej do oceny dopasowania modeli liniowych, a definiowana jako:

\[ R^2=1-\frac{\sum_i(y_i-\hat{y}_i)^2}{\sum_i(y_i-\bar{y})^2}, \tag{4.1}\]

gdzie \(\hat{y}_i\) jest \(i\)-tą wartością przewidywaną na podstawie modelu, \(\bar{y}\) jest średnią zmiennej wynikowej, a \(y_i\) jest \(i\)-tą wartością obserwowaną. Już na kursie modeli liniowych dowiedzieliśmy się o wadach tak zdefiniowanej miary. Wśród nich należy wymienić przede wszystkim fakt, iż dołączając do modelu zmienne, których zdolność predykcyjna jest nieistotna3, to i tak rośnie \(R^2\)

3 czyli nie mają znaczenia w przewidywaniu wartości wynikowej

4 drzewo składa się tylko z korzenia

W przypadku modeli liniowych wprowadzaliśmy korektę eliminującą tą wadę, jednak w przypadku modeli predykcyjnych skorygowana miara \(R^2_{adj}\) nie wystarcza. W sytuacji gdy modele mają bardzo słabą moc predykcyjną, czyli są np. drzewem regresyjnym bez żadnej reguły podziału4, wówczas można otrzymać ujemne wartości obu miar. Zaleca się zatem wprowadzenie miary, która pozbawiona jest tej wady, a jednocześnie ma tą sama interpretację. Definiuję się ją następująco:

\[ \tilde{R}^2=[\operatorname{Cor}(Y, \hat{Y})]^2. \tag{4.2}\]

Miara zdefiniowana w (4.2) zapewnia nam wartości w przedziale (0,1), a klasyczna miara (4.1) nie (Kvalseth 1985). Tradycyjna jest zdefiniowana w bibliotece yardstick5 pod nazwą rsq_trad, natomiast miara oparta na korelacji jako rsq. Oczywiście interpretacja jest następująca, że jeśli wartość \(\tilde{R}^2\) jest bliska 1, to model jest dobrze dopasowany, a bliskie 0 oznacza słabe dopasowanie.

5 będącej częścią ekosystemu tidymodels

4.1.2 RMSE

Inną powszechnie stosowaną miarą do oceny dopasowania modeli regresyjnych jest pierwiastek błędu średnio-kwadratowego (ang. Root Mean Square Error), zdefiniowany następująco:

\[ RMSE = \sqrt{\frac{\sum_{i=1}^n(y_i-\hat{y}_i)^2}{n}}, \tag{4.3}\]

gdzie \(n\) oznacza liczebność zbioru danych na jakim dokonywana jest ocena dopasowania. Im mniejsza jest wartość błędu RMSE tym lepiej dopasowany jest model. Niestety wadą tej miary jest brak odporności na wartości odstające. Błąd w tym przypadku jest mierzony w tych samych jednostkach co mierzona wielkość wynikowa \(Y\). Do wywołania jej używamy funkcji rmse.

4.1.3 MSE

Ściśle powiązaną miarą dopasowania modelu z RMSE jest błąd średnio-kwadratowy (ang. Mean Square Error). Oczywiście jest on definiowany jako kwadrat RMSE. Interpretacja jest podobna jak w przypadku RMSE. W tym przypadku błąd jest mierzony w jednostkach do kwadratu i również jak w przypadku RMSE miara ta jest wrażliwa na wartości odstające. Wywołujemy ją funkcją mse.

4.1.4 MAE

Chcąc uniknąć (choćby w części) wrażliwości na wartości odstające stosuje się miarę średniego absolutnego błędu (ang. Mean Absolut Error). Definiujemy go następująco:

\[ MAE=\frac{\sum_{i=1}^n\vert y_i-\hat{y}_i\vert}{n}. \tag{4.4}\]

Ponieważ wartości błędów \(y_i-\hat{y}_i\) nie są podnoszone do kwadratu, to miara ta jest mniej wrażliwa na punkty odstające. Interpretacja jej jest podobna jak MSE i RMSE. Do wywołania jej używamy funkcji mae. Błąd w tym przypadku jest również mierzony w tych samych jednostkach co \(Y\).

Wymienione miary błędów są nieunormowane, a dopasowania modeli możemy dokonywać jedynie porównując wynik błędu z wartościami \(Y\), lub też przez porównanie miar dla różnych modeli.

4.1.5 MAPE

Średni bezwzględny błąd procentowy (ang. Mean Absolute Percentage Error) jest przykładem miary błędu wyrażanego w procentach. Definiuje się go następująco:

\[ MAPE=\frac{1}{n}\sum_{i=1}^n\left|\frac{y_i-\hat{y}_i}{y_i}\right|\cdot 100\%. \tag{4.5}\]

Interpretujemy ten błąd podobnie jak poprzednie pomimo, że jest wyrażony w procentach. Do wywołania go w pakiecie yardstick używamy funkcji mape.

4.1.6 MASE

Średni bezwzględny błąd skalowany (ang. Mean Absolute Scaled Error) jest miarą dokładności prognoz. Została zaproponowana w 2005 roku przez statystyka Roba J. Hyndmana i profesora Anne B. Koehler, którzy opisali ją jako “ogólnie stosowaną miarę dokładności prognoz bez problemów widocznych w innych miarach” (Hyndman i Koehler 2006). Średni bezwzględny błąd skalowany ma korzystne właściwości w porównaniu z innymi metodami obliczania błędów prognoz, takimi jak RMSE, i dlatego jest zalecany do określania dokładności prognoz w szeregach czasowych (Franses 2016). Definiujemy go następująco

\[ MASE = \frac{\sum_{i=1}^n\vert y_i-\hat{y}_i\vert}{\sum_{i=1}^n\vert y_i-\bar{y}_i\vert}. \tag{4.6}\]

Dla szeregów czasowych z sezonowością i bez sezonowości definiuje się go jeszcze nieco inaczej (Hyndman i Koehler 2006; 3.4 Evaluating Forecast Accuracy | Forecasting: Principles and Practice (2nd Ed), b.d.). Oczywiście interpretacja jest też podobna jak w przypadku innych miar błędów. Wywołujemy go funkcją mase.

4.1.7 MPE

Średni błąd procentowy (ang. Mean Percentage Error) jest miarą błędu względnego definiowaną nastepująco

\[ MPE = \frac{1}{n}\sum_{i=1}^n\frac{y_i-\hat{y}_i}{y_i}. \tag{4.7}\]

Ponieważ we wzorze wykorzystywane są rzeczywiste, a nie bezwzględne wartości błędów prognozy, dodatnie i ujemne błędy prognozy mogą się wzajemnie kompensować. W rezultacie wzór ten można wykorzystać jako miarę błędu systematycznego w prognozach. Wadą tej miary jest to, że jest ona zawsze określona, gdy pojedyncza wartość rzeczywista wynosi zero. Wywołujemy ją za pomocą mpe.

4.1.8 MSD

Średnia znakowa różnic (ang. Mean Signed Deviation), znana również jako średnie odchylenie znakowe i średni błąd znakowy, jest statystyką próbkową, która podsumowuje, jak dobrze szacunki \(\hat{Y}\) pasują do wielkości obserwowanych \(Y\). Definiujemy ją następująco:

\[ MSD = \frac{1}{n}\sum_{i=1}^n(\hat{y}_i-y_i). \tag{4.8}\]

Interpretacja podobnie jak w przypadku innych błędów i mniej wynosi miara tym lepiej dopasowany model. Wywołujemy go funkcją msd.

Istnieje cały szereg miar specjalistycznych rzadziej stosowanych w zagadnieniach regresyjnych. Wśród nich należy wymienić

4.1.9 Funkcja straty Hubera

Funkcja straty Hubera (ang. Huber loss) jest miarą błędu nieco bardziej odporną na punkty odstające niż RMSE. Definiujemy ją następująco:

\[ L_{\delta}(y, \hat{y})= \begin{cases} \frac12 (y_i-\hat{y}_i)^2, &\text{ jeśli }\vert y_i-\hat{y}_i\vert\leq\delta\\ \delta\cdot \vert y_i-\hat{y}_i\vert-\tfrac12\delta, &\text{ w przeciwnym przypadku}. \end{cases} \tag{4.9}\]

W implementacji yardstick \(\delta=1\) natomiast wyliczanie funkcji straty następuje przez uśrednienie po wszystkich obserwacjach. Z definicji widać, że funkcja straty Hubera jest kombinacją MSE i odpowiednio przekształconej miary MAE, w zależności od tego czy predykcja znacząco odbiegają od obserwowanych wartości. Wywołujemy ją przez funkcję huber_loss.

4.1.10 Funkcja straty Pseudo-Hubera

Funkcja straty Pseudo-Hubera (ang. Pseudo-Huber loss) może być stosowana jako gładkie przybliżenie funkcji straty Hubera. Łączy ona najlepsze właściwości straty kwadratowej6 i straty bezwzględnej7, będąc silnie wypukłą, gdy znajduje się blisko celu (minimum) i mniej stromą dla wartości ekstremalnych . Skala, przy której funkcja straty Pseudo-Hubera przechodzi od straty L2 dla wartości bliskich minimum do straty L1 może być kontrolowana przez parametr \(\delta\). Funkcja straty Pseudo-Hubera zapewnia, że pochodne są ciągłe dla wszystkich stopni . Definiujemy ją następująco :

6 inaczej w normie L2

7 w normie L1

\[ L_{\delta}(y-\hat{y})=\delta^2\left(\sqrt{1+((y-\hat{y})/\delta)^2}-1\right). \tag{4.10}\] Wywołujemy ją za pomocą funkcji huber_loss_pseudo.

4.1.11 Logarytm funkcji straty dla rozkładu Poissona

Logarytm funkcji straty dla rozkładu Poissona (ang. Mean log-loss for Poisson data) definiowany jest w następujący sposób:

\[ \mathcal{L}=\frac1n\sum_{i=11}^n(\hat{y}_i-y_i\cdot \ln(\hat{y}_i)). \]

Wywołujemy go funkcją poisson_log_los.

4.1.12 SMAPE

Symetryczny średni bezwzględny błąd procentowy (ang. Symmetric Mean Absolute Percentage Error) jest miarą dokładności opartą na błędach procentowych (lub względnych). Definiujemy ją następująco:

\[ SMAPE = \frac1n\sum_{i=1}^n\frac{\vert y_i-\hat{y}_i\vert}{(|y_i|+|\hat{y}_i|)/2}\cdot100\%. \tag{4.11}\]

Wywołujemy go funkcją smape.

4.1.13 RPD

Stosunek wydajności do odchylenia standardowego (ang. Ratio of Performance to Deviation) definiujemy jako

\[ RPD = \frac{SD}{RMSE}, \tag{4.12}\]

gdzie \(SD\) oczywiście oznacza odchylenie standardowe zmiennej zależnej. Tym razem interpretujemy go w ten sposób, że im wyższa jest wartość RPD tym lepiej dopasowany model. Wywołujemy za pomocą rpd.

W szczególności w dziedzinie spektroskopii, stosunek wydajności do odchylenia (RPD) został użyty jako standardowy sposób raportowania jakości modelu. Jest to stosunek odchylenia standardowego zmiennej do błędu standardowego przewidywania tej zmiennej przez dany model. Jednak jego systematyczne stosowanie zostało skrytykowane przez kilku autorów, ponieważ użycie odchylenia standardowego do reprezentowania rozrzutu zmiennej może być niewłaściwe w przypadku zbiorów danych z asymetrią rozkładów. Stosunek wydajności do rozstępu międzykwartylowego został wprowadzony przez Bellon-Maurel i in. (2010) w celu rozwiązania niektórych z tych problemów i uogólnienia RPD na zmienne o rozkładzie nienormalnym.

4.1.14 RPIQ

Stosunek wartości do rozstępu międzykwartylowego (ang. Ratio of Performance to Inter-Quartile) definiujemy następująco:

\[ RPIQ = \frac{IQ}{RMSE}, \tag{4.13}\]

gdzie \(IQ\) oznacza rozstęp kwartylowy zmiennej zależnej. Wywołujemy go przez funkcję rpiq.

4.1.15 CCC

Korelacyjny współczynnik zgodności (ang. Concordance Correlation Coefficient) mierzy zgodność pomiędzy wartościami predykcji i obserwowanymi. Definiujemy go w następujący sposób:

\[ CCC = \frac{2\rho\sigma_y\sigma_{\hat{y}}}{\sigma^2_{y}+\sigma^2_{\hat{y}}+(\mu_y-\mu_{\hat{y}})^2}, \]

gdzie \(\mu_y,\mu_{\hat{y}}\) oznaczają średnią wartości obserwowanych i przewidywanych odpowiednio, \(\sigma_{y},\sigma_{\hat{y}}\) stanowią natomiast odchylenia standardowe tych wielkości. \(\rho\) jest współczynnikiem korelacji pomiędzy \(Y\) i \(\hat{Y}\). Wywołanie w R to funkcja ccc.

4.1.16 Podsumowanie miar dla modeli regresyjnych

Wśród miar dopasowania modelu można wyróżnić, te które mierzą zgodność pomiędzy wartościami obserwowanymi a przewidywanymi, wyrażone często pewnego rodzaju korelacjami (lub ich kwadratami), a interpretujemy je w ten sposób, że im wyższe wartości tych współczynników tym bardziej zgodne są predykcje z obserwacjami. Drugą duża grupę miar stanowią błędy (bezwzględne i względne), które mierzą w różny sposób różnice pomiędzy wartościami obserwowanymi i przewidywanymi. Jedne są bardziej odporne wartości odstające inne mniej, a wszystkie interpretujemy tak, że jeśli ich wartość jest mniejsza tym lepiej jest dopasowany model.

Przykład 4.1 Dla zilustrowania działania wspomnianych miar przeanalizujemy przykład modelu regresyjnego. Dla przykładu rozwiążemy zadanie przewidywania wytrzymałości betonu na podstawie jego parametrów. Do tego celu użyjemy danych ze zbioru concrete pakietu modeldata.(Yeh 2006)

Kod
library(tidymodels)

# charakterystyka danych
glimpse(concrete)
Rows: 1,030
Columns: 9
$ cement               <dbl> 540.0, 540.0, 332.5, 332.5, 198.6, 266.0, 380.0, …
$ blast_furnace_slag   <dbl> 0.0, 0.0, 142.5, 142.5, 132.4, 114.0, 95.0, 95.0,…
$ fly_ash              <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ water                <dbl> 162, 162, 228, 228, 192, 228, 228, 228, 228, 228,…
$ superplasticizer     <dbl> 2.5, 2.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,…
$ coarse_aggregate     <dbl> 1040.0, 1055.0, 932.0, 932.0, 978.4, 932.0, 932.0…
$ fine_aggregate       <dbl> 676.0, 676.0, 594.0, 594.0, 825.5, 670.0, 594.0, …
$ age                  <int> 28, 28, 270, 365, 360, 90, 365, 28, 28, 28, 90, 2…
$ compressive_strength <dbl> 79.99, 61.89, 40.27, 41.05, 44.30, 47.03, 43.70, …
Kod
# modelowania dokonamy bez szczególnego uwzględnienia charakteru zmiennych,
# tuningowania i innych czynności, które będą nam towarzyszyć w normalnej
# budowie modelu

# podział danych na uczące i testowe
set.seed(44)
split <- initial_split(data = concrete,
                       prop = 0.7)
train_data <- training(split)
test_data <- testing(split)

# określenie modeli, wybrałem kNN
knn5 <-
  nearest_neighbor(neighbors = 5) |> 
  set_engine('kknn') %>%
  set_mode('regression')

knn25 <-
  nearest_neighbor(neighbors = 25) |> 
  set_engine('kknn') %>%
  set_mode('regression')

# uczymy modele
fit5 <- knn5 |> 
  fit(compressive_strength~., data = train_data)

fit25 <- knn25 |> 
  fit(compressive_strength~., data = train_data)

# obliczamy predykcję dla obu modeli na obu zbiorach
pred_train5 <- predict(fit5, train_data)
pred_train25 <- predict(fit25, train_data)
pred_test5 <- predict(fit5, test_data)
pred_test25 <- predict(fit25, test_data)
Kod
bind_cols(obs = c(train_data$compressive_strength, test_data$compressive_strength),
          pred5 = c(pred_train5$.pred, pred_test5$.pred),
          pred25 = c(pred_train25$.pred, pred_test25$.pred)) |> 
  mutate(sample = rep(c("train", "test"), c(nrow(train_data), nrow(test_data)))) |> 
  pivot_longer(cols = c(pred5, pred25),
               names_to = "model",
               values_to = "pred") |> 
  mutate(model = case_when(
    model == "pred5" ~ "knn5",
    model == "pred25" ~ "knn25"
  )) |> 
  ggplot(aes(x = obs, y = pred))+
  geom_point(alpha = 0.1)+
  geom_abline(intercept = 0, 
              slope = 1)+
  facet_grid(sample~model)+
  coord_obs_pred()
Rys. 4.1: Graficzne porównanie obu modeli na obu zbiorach
Kod
# podsumowanie za pomocą miary R2
bind_cols(obs = c(train_data$compressive_strength, test_data$compressive_strength),
          pred5 = c(pred_train5$.pred, pred_test5$.pred),
          pred25 = c(pred_train25$.pred, pred_test25$.pred)) |> 
  mutate(sample = rep(c("train", "test"), c(nrow(train_data), nrow(test_data)))) |> 
  pivot_longer(cols = c(pred5, pred25),
               names_to = "model",
               values_to = "pred") |> 
  group_by(model, sample) |> 
  rsq(truth = obs, estimate = pred) |> 
  arrange(model)
# A tibble: 4 × 5
  model  sample .metric .estimator .estimate
  <chr>  <chr>  <chr>   <chr>          <dbl>
1 pred25 test   rsq     standard       0.645
2 pred25 train  rsq     standard       0.787
3 pred5  test   rsq     standard       0.737
4 pred5  train  rsq     standard       0.929
Kod
# można też podsumować od razu kilkoma miarami
# będa miary domyślne dla modelu regresyjnego
bind_cols(obs = c(train_data$compressive_strength, test_data$compressive_strength),
          pred5 = c(pred_train5$.pred, pred_test5$.pred),
          pred25 = c(pred_train25$.pred, pred_test25$.pred)) |> 
  mutate(sample = rep(c("train", "test"), c(nrow(train_data), nrow(test_data)))) |> 
  pivot_longer(cols = c(pred5, pred25),
               names_to = "model",
               values_to = "pred") |> 
  group_by(model, sample) |> 
  metrics(truth = obs, estimate = pred) |> 
  arrange(model, .metric)
# A tibble: 12 × 5
   model  sample .metric .estimator .estimate
   <chr>  <chr>  <chr>   <chr>          <dbl>
 1 pred25 test   mae     standard       7.73 
 2 pred25 train  mae     standard       6.50 
 3 pred25 test   rmse    standard       9.74 
 4 pred25 train  rmse    standard       8.22 
 5 pred25 test   rsq     standard       0.645
 6 pred25 train  rsq     standard       0.787
 7 pred5  test   mae     standard       6.33 
 8 pred5  train  mae     standard       3.45 
 9 pred5  test   rmse    standard       8.26 
10 pred5  train  rmse    standard       4.68 
11 pred5  test   rsq     standard       0.737
12 pred5  train  rsq     standard       0.929
Kod
# możemy zmienić parametry niektórych miar
huber_loss2 <- metric_tweak("huber_loss2", huber_loss, delta = 2)

# można również wybrać jakie miary zostana użyte
selected_metrics <- metric_set(ccc, rpd, mape, huber_loss2)


bind_cols(obs = c(train_data$compressive_strength, test_data$compressive_strength),
          pred5 = c(pred_train5$.pred, pred_test5$.pred),
          pred25 = c(pred_train25$.pred, pred_test25$.pred)) |> 
  mutate(sample = rep(c("train", "test"), c(nrow(train_data), nrow(test_data)))) |> 
  pivot_longer(cols = c(pred5, pred25),
               names_to = "model",
               values_to = "pred") |> 
  group_by(model, sample) |> 
  selected_metrics(truth = obs, estimate = pred) |> 
  arrange(model, sample)
# A tibble: 16 × 5
   model  sample .metric     .estimator .estimate
   <chr>  <chr>  <chr>       <chr>          <dbl>
 1 pred25 test   ccc         standard       0.750
 2 pred25 test   rpd         standard       1.64 
 3 pred25 test   mape        standard      30.9  
 4 pred25 test   huber_loss2 standard      13.6  
 5 pred25 train  ccc         standard       0.851
 6 pred25 train  rpd         standard       2.07 
 7 pred25 train  mape        standard      24.8  
 8 pred25 train  huber_loss2 standard      11.1  
 9 pred5  test   ccc         standard       0.844
10 pred5  test   rpd         standard       1.93 
11 pred5  test   mape        standard      24.1  
12 pred5  test   huber_loss2 standard      10.8  
13 pred5  train  ccc         standard       0.958
14 pred5  train  rpd         standard       3.64 
15 pred5  train  mape        standard      12.8  
16 pred5  train  huber_loss2 standard       5.19 

W przypadku gdybyśmy chcieli zdefiniować własną miarę, to oczywiście jest taka możliwość8 polecam stronę pakietu yardstick - https://www.tidymodels.org/learn/develop/metrics/.

8 choć liczba już istniejących jest imponująca

4.2 Miary dopasowania modeli klasyfikacyjnych

Jak to zostało wspomniane wcześniej w modelach klasyfikacyjnych można podzielić miary dopasowania na te, które dotyczą modeli z binarną zmienną wynikową i ze zmienna wielostanową. Miary można też podzielić na te, które zależą od prawdopodobieństwa poszczególnych stanów i te, które zależą tylko od klasyfikacji wynikowej.

Do wyliczenia miar probabilistycznych konieczne jest wyliczenie predykcji z prawdopodobieństwami poszczególnych stanów. Aby uzyskać taki efekt wystarczy w predykcji modelu użyć parametru type = "prob". W przykładzie podsumowującym miary będzie to zilustrowane.

Na to, aby przybliżyć miary dopasowania opartych o prawdopodobieństwa stanów, konieczne jest wprowadzenie pojęcia macierzy klasyfikacji (ang. confusion matrix). Można je stosować zarówno do klasyfikacji dwustanowej, jak i wielostanowej. Użyjemy przykładu binarnego aby zilustrować szczegóły tej macierzy.

Kod
# import danych do przykładu
data(two_class_example)

# kilka pierwszych wierszy wyników predykcji
head(two_class_example)
   truth      Class1       Class2 predicted
1 Class2 0.003589243 0.9964107574    Class2
2 Class1 0.678621054 0.3213789460    Class1
3 Class2 0.110893522 0.8891064779    Class2
4 Class1 0.735161703 0.2648382969    Class1
5 Class2 0.016239960 0.9837600397    Class2
6 Class1 0.999275071 0.0007249286    Class1
Kod
# confusion matrix
two_class_example |> 
  conf_mat(truth, predicted) |> 
  autoplot(type = "heatmap")
Rys. 4.2: Przykładowa macierz klasyfikacji

Aby przedstawić poszczególne miary na podstawie macierzy klasyfikacji wystarczy przywołać ilustrację z Wikipedii, która w genialny sposób podsumowuje większość miar.

Rys. 4.3: Macierz klasyfikacji

Na podstawie tej macierzy możemy ocenić dopasowanie modelu za pomocą:

  • accuacy - informuje o odsetku poprawnie zaklasyfikowanych obserwacji. Jest bardzo powszechnie stosowaną miarą dopasowania modelu choć ma jedną poważną wadę. Mianowicie w przypadku modeli dla danych z wyraźną dysproporcją jednej z klas (powiedzmy jedna stanowi 95% wszystkich obserwacji), może się zdarzyć sytuacja, że nawet bezsensowny model, czyli taki, który zawsze wskazuje tą właśnie wartość, będzie miał accuracy na poziomie 95%.

  • kappa - miara podobna miarą do accuracy i jest bardzo przydatna, gdy jedna lub więcej klas dominuje. Definiujemy ją następująco \(\kappa = \frac{p_o-p_e}{1-p_e}\), gdzie \(p_o,p_e\) są odpowiednio zgodnością obserwowaną i oczekiwaną. Zgodność obserwowana jest odsetkiem obserwacji poprawnie zaklasyfikowanych, a oczekiwana to zgodność wynikająca z przypadku.

  • precision - oznaczana też czasem jako PPV (ang. Positive Predictive Value) oznacza stosunek poprawnie zaklasyfikowanych wartości true positive (TP) do wszystkich przewidywanych wartości pozytywnych (ang. positive predictive).

  • recall - nazywany także sensitivity lub True Positive Rate (TPR), który stanowi stosunek true positive do wszystkich przypadków positive.

  • specificity - nazywane również True Negative Rate (TNR), wyraża się stosunkiem pozycji true negative do wszystkich obserwacji negative.

  • negative predictive value (NPV) - oznaczane czasem też jako false omission rate jest liczone jako stosunek false negative do wszystkich przewidywanych negative (PN).

  • \(F_1\) - jest miarą zdefiniowaną jako \(\frac{2PPV*TPR}{PPV+TPR}\).

  • MCC - Mathews Correlation Coeficient - jest zdefiniowany jako \(\sqrt{TPR*TNR*PPV*NPV}-\sqrt{FNR*FPR*NPV*FDR}\). Istnieje również odmiana tej miary dla przypadku wielostanowej zmiennej wynikowej.

  • balanced accuracy - liczona jako średnia sensitivity i specificity.

  • detection prevalence - zdefiniowana jako stosunek poprawnie przewidywanych obserwacji do liczby wszystkich przewidywanych wartości.

  • J index - metryka Youden’a definiowana jako sensitivity + specificity -1, często jest wykorzystywana do określenia poziomu odcięcia prawdopodobieństwa zdarzenia wyróżnionego (ang. threshold).

  • koszt niepoprawnej klasyfikacji - czasami niektóre błędy klasyfikacji są mniej kosztowne z punktu widzenie badacza, a inne bardziej. Wówczas można przypisać koszty błędnych klasyfikacji do poszczególnych klas, nakładając kary za błędne przypisane do innej klasy i w ten sposób zapobiegać takim sytuacjom.

  • średnia logarytmu funkcji straty (ang. log loss) - określana też w literaturze jako binary cross-entropy dla przypadku zmiennej wynikowej dwustanowej i multilevel cross-entropy albo categorical cross-entropy w przypadku wielostanowej klasyfikacji. Definiuje się ją następująco:

    \[ \mathcal{L} = \frac1n\sum_{i=1}^n\left[y_i\log(\hat{y}_i)+(1-y_i)\log(1-\hat{y}_i)\right], \tag{4.14}\] gdzie \(y_i\) jest indykatorem klasy wyróżnionej dla \(i\)-tej obserwacji, a \(\hat{y}_i\) prawdopodobieństwem wyróżnionego stanu \(i\)-tej obserwacji. Piękną rzeczą w tej definicji jest to, że jest ona ściśle związana z teorią informacji: log-loss jest entropią krzyżową pomiędzy rozkładem prawdziwych etykiet a przewidywaniami i jest bardzo blisko związana z tym, co jest znane jako entropia względna lub rozbieżność Kullbacka-Leiblera. Entropia mierzy nieprzewidywalność czegoś. Entropia krzyżowa zawiera entropię prawdziwego rozkładu plus dodatkową nieprzewidywalność, gdy ktoś zakłada inny rozkład niż prawdziwy. Tak więc log-loss jest miarą z teorii informacji pozwalającą zmierzyć “dodatkowy szum”, który powstaje w wyniku użycia predykcji w przeciwieństwie do prawdziwych etykiet. Minimalizując entropię krzyżową, maksymalizujemy dokładność klasyfikatora. Log-loss, czyli strata logarytmiczna, wnika w najdrobniejsze szczegóły działania klasyfikatora.

    Prawdopodobieństwo można rozumieć jako miernik zaufania. Jeśli prawdziwa etykieta to 0, ale klasyfikator ocenia, że należy ona do klasy 1 z prawdopodobieństwem 0,51, to pomimo tego, że klasyfikator popełniłby błąd, jest to niewielki błąd, ponieważ prawdopodobieństwo jest bardzo bliskie granicy decyzji 0,5. Log-loss jest subtelną miarą dokładności.

Należy pamiętać, że większość wspomnianych miar opiera się na wartościach z macierzy klasyfikacji. Przy czym aby obserwacje zaklasyfikować do jednej z klas należy przyjąć pewien punkt odcięcia (threshold) prawdopodobieństwa, od którego przewidywana wartość będzie przyjmowała stan “1”. Domyślnie w wielu modelach ten punkt jest ustalony na poziomie 0,5. Nie jest on jednak optymalny ze względu na jakość klasyfikacji. Zmieniając ten próg otrzymamy różne wartości specificity, sensitivity, precision, recall, itd. Istnieją kryteria doboru progu odcięcia, np. oparte na wartości Youdena, F1, średniej geometrycznej itp. W przykładzie prezentowanym poniżej pokażemy zastosowanie dwóch z tych technik. Bez względu na przyjęty poziom odcięcia istnieją również miary i wykresy, które pozwalają zilustrować jakość modelu. Należą do nich:

  • wykresy:
    • ROC - Receiver Operating Characteristic - krzywa, która przedstawia kompromis pomiędzy sensitivity i specificity dla różnych poziomów odcięcia. Ta egzotycznie brzmiąca nazwa wywodzi się z analizy sygnałów radiowych i została spopularyzowana w 1978 roku przez Charlesa Metza w artykule “Basic Principles of ROC Analysis”. Krzywa ROC pokazuje czułość klasyfikatora poprzez wykreślenie TPR do FPR. Innymi słowy, pokazuje ona, ile poprawnych pozytywnych klasyfikacji można uzyskać, gdy dopuszcza się coraz więcej fałszywych pozytywów. Idealny klasyfikator, który nie popełnia żadnych błędów, osiągnąłby natychmiast 100% wskaźnik prawdziwych pozytywów, bez żadnych fałszywych pozytywów - w praktyce prawie nigdy się to nie zdarza.

    • PRC - Precision-Recall Curve - krzywa, która pokazuje kompromis pomiędzy precision i recall. Precision i recall to tak naprawdę dwie metryki. Jednak często są one używane razem. Precision odpowiada na pytanie: “Z elementów, które klasyfikator przewidział jako pozytywnych ile jest rzeczywiście pozytywnych?”. Natomiast recall odpowiada na pytanie: “Spośród wszystkich elementów, które są pozytywne, ile zostało przewidzianych jako takie przez klasyfikator?”. Krzywa PRC to po prostu wykres z wartościami Precision na osi y i Recall na osi x. Innymi słowy, krzywa PRC zawiera TP/(TP+FP) na osi y oraz TP/(TP+FN) na osi x.

    • Krzywa wzrostu (ang. Gain Curve) - to krzywa przedstawiająca stosunek skumulowanej liczby pozytywnych (wyróżnionych) obserwacji w decylu do całkowitej liczby pozytywnych obserwacji w danych.

    • Krzywa wyniesienia (ang. Lift Curve) - jest stosunkiem liczby pozytywnych obserwacji w \(i\)-tym decylu na podstawie modelu do oczekiwanej liczby pozytywnych obserwacji należących do \(i\)-tego decyla na podstawie modelu losowego.

  • miary:
    • AUC - Area Under ROC Curve - mierzy pole pod krzywą ROC. Krzywa ROC nie jest pojedynczą liczbą ale całą krzywą. Dostarcza ona szczegółowych informacji o zachowaniu klasyfikatora, ale trudno jest szybko porównać wiele krzywych ROC ze sobą. W szczególności, jeśli ktoś chciałby zastosować jakiś automatyczny mechanizm tuningowania hiperparametrów, maszyna potrzebowałaby wymiernego wyniku zamiast wykresu, który wymaga wizualnej inspekcji. AUC jest jednym ze sposobów podsumowania krzywej ROC w jedną liczbę, tak aby można było ją łatwo i automatycznie porównać. Dobra krzywa ROC ma dużo miejsca pod sobą (ponieważ prawdziwy wskaźnik pozytywny bardzo szybko wzrasta do 100%). Zła krzywa ROC obejmuje bardzo mały obszar. Tak więc wysokie AUC jest sygnałem dobrego dopasowania modelu.

    • PRAUC - Area Under Precision-Racall Curve - mierzy pole pod krzywą P-R.

    • Pole pod krzywą wzrosu.

    • Pole pod krzywą wyniesienia.

Przykład 4.2 Tym razem zbudujemy model klasyfikacyjny dla zmiennej wynikowej dwustanowej. Dane pochodzą ze zbioru attrition pakietu modeldata. Naszym zadaniem będzie zbudować modeli przewidujący odejścia z pracy.

Kod
str(attrition)
'data.frame':   1470 obs. of  31 variables:
 $ Age                     : int  41 49 37 33 27 32 59 30 38 36 ...
 $ Attrition               : Factor w/ 2 levels "No","Yes": 2 1 2 1 1 1 1 1 1 1 ...
 $ BusinessTravel          : Factor w/ 3 levels "Non-Travel","Travel_Frequently",..: 3 2 3 2 3 2 3 3 2 3 ...
 $ DailyRate               : int  1102 279 1373 1392 591 1005 1324 1358 216 1299 ...
 $ Department              : Factor w/ 3 levels "Human_Resources",..: 3 2 2 2 2 2 2 2 2 2 ...
 $ DistanceFromHome        : int  1 8 2 3 2 2 3 24 23 27 ...
 $ Education               : Ord.factor w/ 5 levels "Below_College"<..: 2 1 2 4 1 2 3 1 3 3 ...
 $ EducationField          : Factor w/ 6 levels "Human_Resources",..: 2 2 5 2 4 2 4 2 2 4 ...
 $ EnvironmentSatisfaction : Ord.factor w/ 4 levels "Low"<"Medium"<..: 2 3 4 4 1 4 3 4 4 3 ...
 $ Gender                  : Factor w/ 2 levels "Female","Male": 1 2 2 1 2 2 1 2 2 2 ...
 $ HourlyRate              : int  94 61 92 56 40 79 81 67 44 94 ...
 $ JobInvolvement          : Ord.factor w/ 4 levels "Low"<"Medium"<..: 3 2 2 3 3 3 4 3 2 3 ...
 $ JobLevel                : int  2 2 1 1 1 1 1 1 3 2 ...
 $ JobRole                 : Factor w/ 9 levels "Healthcare_Representative",..: 8 7 3 7 3 3 3 3 5 1 ...
 $ JobSatisfaction         : Ord.factor w/ 4 levels "Low"<"Medium"<..: 4 2 3 3 2 4 1 3 3 3 ...
 $ MaritalStatus           : Factor w/ 3 levels "Divorced","Married",..: 3 2 3 2 2 3 2 1 3 2 ...
 $ MonthlyIncome           : int  5993 5130 2090 2909 3468 3068 2670 2693 9526 5237 ...
 $ MonthlyRate             : int  19479 24907 2396 23159 16632 11864 9964 13335 8787 16577 ...
 $ NumCompaniesWorked      : int  8 1 6 1 9 0 4 1 0 6 ...
 $ OverTime                : Factor w/ 2 levels "No","Yes": 2 1 2 2 1 1 2 1 1 1 ...
 $ PercentSalaryHike       : int  11 23 15 11 12 13 20 22 21 13 ...
 $ PerformanceRating       : Ord.factor w/ 4 levels "Low"<"Good"<"Excellent"<..: 3 4 3 3 3 3 4 4 4 3 ...
 $ RelationshipSatisfaction: Ord.factor w/ 4 levels "Low"<"Medium"<..: 1 4 2 3 4 3 1 2 2 2 ...
 $ StockOptionLevel        : int  0 1 0 0 1 0 3 1 0 2 ...
 $ TotalWorkingYears       : int  8 10 7 8 6 8 12 1 10 17 ...
 $ TrainingTimesLastYear   : int  0 3 3 3 3 2 3 2 2 3 ...
 $ WorkLifeBalance         : Ord.factor w/ 4 levels "Bad"<"Good"<"Better"<..: 1 3 3 3 3 2 2 3 3 2 ...
 $ YearsAtCompany          : int  6 10 0 8 2 7 1 1 9 7 ...
 $ YearsInCurrentRole      : int  4 7 0 7 2 7 0 0 7 7 ...
 $ YearsSinceLastPromotion : int  0 1 0 3 2 3 0 0 1 7 ...
 $ YearsWithCurrManager    : int  5 7 0 0 2 6 0 0 8 7 ...
Kod
# podział zbioru na uczący i testowy
set.seed(44)
split <- initial_split(attrition, prop = 0.7, strata = "Attrition")
train_data <- training(split)
test_data <- testing(split)

# określam model
lr_mod <- logistic_reg() |> 
  set_engine("glm") |> 
  set_mode("classification")

# uczę model
lr_fit <- lr_mod |> 
  fit(Attrition ~ ., data = train_data)

# podsumowanie modelu
lr_fit |> 
  tidy() 
# A tibble: 58 × 5
   term                             estimate   std.error statistic   p.value
   <chr>                               <dbl>       <dbl>     <dbl>     <dbl>
 1 (Intercept)                     -3.41     1261.       -0.00270  0.998    
 2 Age                             -0.0375      0.0179   -2.09     0.0364   
 3 BusinessTravelTravel_Frequently  2.14        0.546     3.92     0.0000875
 4 BusinessTravelTravel_Rarely      1.31        0.505     2.60     0.00942  
 5 DailyRate                       -0.000213    0.000279 -0.766    0.444    
 6 DepartmentResearch_Development   0.783    1261.        0.000621 1.00     
 7 DepartmentSales                 13.7      1115.        0.0123   0.990    
 8 DistanceFromHome                 0.0452      0.0137    3.30     0.000964 
 9 Education.L                      0.353       0.435     0.811    0.417    
10 Education.Q                      0.170       0.372     0.458    0.647    
# ℹ 48 more rows

Teraz korzystając z różnych miar podsumujemy dopasowanie modelu.

Kod
# predykcja z modelu przyjmując threshold = 0.5
pred_class <- predict(lr_fit, new_data = test_data)

# predkcja (prawdopodobieństwa klas)
pred_prob <- predict(lr_fit, new_data = test_data, type = "prob")

# ale można też tak
pred <- augment(lr_fit, test_data) |> 
  select(Attrition, .pred_class, .pred_No, .pred_Yes)

# macierz klasyfikacji
cm <- pred |> 
  conf_mat(truth = Attrition, estimate = .pred_class)
cm
          Truth
Prediction  No Yes
       No  352  39
       Yes  18  33
Kod
# A tibble: 13 × 3
   .metric              .estimator .estimate
   <chr>                <chr>          <dbl>
 1 accuracy             binary         0.871
 2 kap                  binary         0.464
 3 sens                 binary         0.951
 4 spec                 binary         0.458
 5 ppv                  binary         0.900
 6 npv                  binary         0.647
 7 mcc                  binary         0.474
 8 j_index              binary         0.410
 9 bal_accuracy         binary         0.705
10 detection_prevalence binary         0.885
11 precision            binary         0.900
12 recall               binary         0.951
13 f_meas               binary         0.925

Możemy też narysować krzywe, które nam pokażą, czy dla innych wartości progu model też dobrze przewiduje klasy wynikowe.

Kod
#ROC
pred |> 
  roc_curve(truth = Attrition, .pred_Yes, event_level = "second") |> 
  autoplot()

Kod
#PRC
pred |> 
  pr_curve(truth = Attrition, .pred_Yes, event_level = "second") |> 
  autoplot()

Kod
#AUC
pred |> 
  roc_auc(truth = Attrition, .pred_Yes, event_level = "second") 
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 roc_auc binary         0.808
Kod
#PRAUC
pred |> 
  pr_auc(truth = Attrition, .pred_Yes, event_level = "second") 
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 pr_auc  binary         0.569

Wybór optymalnego progu odcięcia.

Kod
library(probably)

# ustalam zakres threshold
thresholds <- seq(0.01,1, by = 0.01)

# poszukuje najlepszego progu ze względu kryterium Youden'a
pred |>
  threshold_perf(Attrition, .pred_Yes, thresholds, event_level = "second") |>
  pivot_wider(names_from = .metric, values_from = .estimate) |>
  arrange(-j_index)
# A tibble: 100 × 5
   .threshold .estimator sensitivity specificity j_index
        <dbl> <chr>            <dbl>       <dbl>   <dbl>
 1       0.19 binary           0.722       0.838   0.560
 2       0.17 binary           0.736       0.816   0.552
 3       0.18 binary           0.722       0.824   0.547
 4       0.16 binary           0.736       0.808   0.544
 5       0.2  binary           0.694       0.846   0.540
 6       0.22 binary           0.681       0.857   0.537
 7       0.15 binary           0.736       0.797   0.533
 8       0.21 binary           0.681       0.851   0.532
 9       0.12 binary           0.75        0.773   0.523
10       0.26 binary           0.639       0.884   0.523
# ℹ 90 more rows
Kod
# predykjca dla optymalnego progu
pred.optim <- pred |> 
  mutate(class = as.factor(ifelse(.pred_Yes > 0.19, "Yes", "No")))

# macierz klasyfikacji
cm2 <- pred.optim |> 
  conf_mat(truth = Attrition, estimate = class)
cm2
          Truth
Prediction  No Yes
       No  310  20
       Yes  60  52
Kod
summary(cm2)
# A tibble: 13 × 3
   .metric              .estimator .estimate
   <chr>                <chr>          <dbl>
 1 accuracy             binary         0.819
 2 kap                  binary         0.458
 3 sens                 binary         0.838
 4 spec                 binary         0.722
 5 ppv                  binary         0.939
 6 npv                  binary         0.464
 7 mcc                  binary         0.475
 8 j_index              binary         0.560
 9 bal_accuracy         binary         0.780
10 detection_prevalence binary         0.747
11 precision            binary         0.939
12 recall               binary         0.838
13 f_meas               binary         0.886

4.2.1 Miary dopasowania dla modeli ze zmienną wynikową wieloklasową

Wspomniane zostało, że miary dedykowane dla modeli binarnych można również wykorzystać do modeli ze zmienną zależną wielostanową. Oczywiście wówczas trzeba użyć pewnego rodzaju uśredniania. Implementacje wieloklasowe wykorzystują mikro, makro i makro-ważone uśrednianie, a niektóre metryki mają swoje własne wyspecjalizowane implementacje wieloklasowe.

4.2.1.1 Makro uśrednianie

Makro uśrednianie redukuje wieloklasowe predykcje do wielu zestawów przewidywań binarnych. Oblicza się odpowiednią metrykę dla każdego z przypadków binarnych, a następnie uśrednia wyniki. Jako przykład, rozważmy precision. W przypadku wieloklasowym, jeśli istnieją poziomy A, B, C i D, makro uśrednianie redukuje problem do wielu porównań jeden do jednego. Kolumny truth i estimate są rekodowane tak, że jedynymi dwoma poziomami są A i inne, a następnie precision jest obliczana w oparciu o te rekodowane kolumny, przy czym A jest “wyróżnioną” kolumną. Proces ten jest powtarzany dla pozostałych 3 poziomów, aby uzyskać łącznie 4 wartości precyzji. Wyniki są następnie uśredniane.

Formuła dla \(k\) klas wynikowych prezentuje się następująco:

\[ Pr_{macro} = \frac{Pr_1+Pr_2+\ldots+Pr_k}{k}, \tag{4.15}\]

gdzie \(Pr_i\) oznacza precision dla \(i\)-tej klasy.

4.2.1.2 Makro-ważone uśrednianie

Makro-ważone uśrednianie jest co do zasady podobne do metody makro uśredniania, z tą jednak zmianą, że wagi poszczególnych czynników w średniej zależą od liczności tych klas, co sprawia, że miara ta jest bardziej optymalna w przypadku wyraźnych dysproporcji zmiennej wynikowej. Formalnie obliczamy to wg reguły:

\[ Pr_{weighted-macro}=Pr_1\frac{\#Obs_1}{n}+Pr_2\frac{\#Obs_2}{n}+\ldots+Pr_k\frac{\#Obs_k}{n}, \tag{4.16}\]

gdzie \(\#Obs_i\) oznacza liczbę obserwacji w grupie \(i\)-tej, a \(n\) jest liczebnością całego zbioru.

4.2.1.3 Mikro uśrednianie

Mikro uśrednianie traktuje cały zestaw danych jako jeden wynik zbiorczy i oblicza jedną metrykę zamiast \(k\) metryk, które są uśredniane. Dla precision działa to poprzez obliczenie wszystkich true positive wyników dla każdej klasy i użycie tego jako licznika, a następnie obliczenie wszystkich true positive i false positive wyników dla każdej klasy i użycie tego jako mianownika.

\[ Pr_{micro} = \frac{TP_1+TP_2+\ldots TP_k}{(TP_1+TP_2+\ldots TP_k)+(FP_1+FP_2+\ldots FP_k)}. \tag{4.17}\]

W tym przypadku, zamiast klas o równej wadze, mamy obserwacje z równą wagą. Dzięki temu klasy z największą liczbą obserwacji mają największy wpływ na wynik.

Przykład 4.3 Przykład użycia miar dopasowania modelu dla zmiennych wynikowych wieloklasowych.

Kod
# predykcja wykonana dla sprawdzianu krzyżowego
# bedzie nas interesować tylko wynik pierwszego folda
head(hpc_cv)
  obs pred        VF          F           M            L Resample
1  VF   VF 0.9136340 0.07786694 0.008479147 1.991225e-05   Fold01
2  VF   VF 0.9380672 0.05710623 0.004816447 1.011557e-05   Fold01
3  VF   VF 0.9473710 0.04946767 0.003156287 4.999849e-06   Fold01
4  VF   VF 0.9289077 0.06528949 0.005787179 1.564496e-05   Fold01
5  VF   VF 0.9418764 0.05430830 0.003808013 7.294581e-06   Fold01
6  VF   VF 0.9510978 0.04618223 0.002716177 3.841455e-06   Fold01
Kod
# macierz klasyfikacji
cm <- hpc_cv |> 
  conf_mat(truth = obs, estimate = pred)
cm
          Truth
Prediction   VF    F    M    L
        VF 1620  371   64    9
        F   141  647  219   60
        M     6   24   79   28
        L     2   36   50  111
Kod
# poniższe miary są makro uśrednione
summary(cm)
# A tibble: 13 × 3
   .metric              .estimator .estimate
   <chr>                <chr>          <dbl>
 1 accuracy             multiclass     0.709
 2 kap                  multiclass     0.508
 3 sens                 macro          0.560
 4 spec                 macro          0.879
 5 ppv                  macro          0.631
 6 npv                  macro          0.896
 7 mcc                  multiclass     0.515
 8 j_index              macro          0.440
 9 bal_accuracy         macro          0.720
10 detection_prevalence macro          0.25 
11 precision            macro          0.631
12 recall               macro          0.560
13 f_meas               macro          0.570
Kod
# poniższe miary są makro uśrednione
summary(cm, estimator = "micro")
# A tibble: 13 × 3
   .metric              .estimator .estimate
   <chr>                <chr>          <dbl>
 1 accuracy             multiclass     0.709
 2 kap                  multiclass     0.508
 3 sens                 micro          0.709
 4 spec                 micro          0.903
 5 ppv                  micro          0.709
 6 npv                  micro          0.903
 7 mcc                  multiclass     0.515
 8 j_index              micro          0.612
 9 bal_accuracy         micro          0.806
10 detection_prevalence micro          0.25 
11 precision            micro          0.709
12 recall               micro          0.709
13 f_meas               micro          0.709
Kod
# ROC
hpc_cv |> 
  roc_curve(truth = obs, VF:L) |> 
  autoplot()

Kod
# AUC
hpc_cv |> 
  roc_auc(truth = obs, VF:L)
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 roc_auc hand_till      0.829

4.3 Uwagi końcowe

Stosując jedna miarę dopasowania modelu (bez względu na to czy jest to model klasyfikacyjny czy regresyjny) możemy nie otrzymać optymalnego modelu. Ze względu na definicje miary dopasowania różnią się pomiędzy sobą eksponując nieco inne aspekty. To powoduje, że może się zdarzyć sytuacja, że optymalny model ze względu na \(R^2\) będzie się różnił (nawet znacznie) od modelu optymalizowanego z użyciem RMSE (patrz Rys. 4.4).

Rys. 4.4: Porównanie jakości modeli z wykorzystaniem różnych miar

Model zoptymalizowany pod kątem RMSE ma większą zmienność, ale ma stosunkowo jednolitą dokładność w całym zakresie wyników. Prawy panel pokazuje, że istnieje silniejsza korelacja między wartościami obserwowanymi i przewidywanymi, ale model ten słabo radzi sobie w przewidywaniu skrajnych wartości. Na marginesie można dodać, że jeśli model miałby być stosowany do predykcji (co zdarza się bardzo często w modelach ML), to miara RMSE jest lepsza, natomiast gdy interesują nas poszczególne efekty modelu regresji, wówczas \(R^2\) jest częściej stosowaną miarą oceny dopasowania modelu.

Podobny przykład można przytoczyć również dla modeli klasyfikacyjnych.

Ocena skuteczności danego modelu zależy od tego, do czego będzie on wykorzystywany. Model inferencyjny jest używany przede wszystkim do zrozumienia związków i zazwyczaj kładzie nacisk na wybór (i ważność) rozkładów probabilistycznych i innych cech generatywnych, które definiują model. Dla modelu używanego głównie do przewidywania, w przeciwieństwie do tego, siła predykcyjna ma podstawowe znaczenie, a inne obawy dotyczące podstawowych właściwości statystycznych mogą być mniej ważne. Siła predykcyjna jest zwykle określana przez to, jak blisko nasze przewidywania zbliżają się do obserwowanych danych, tj. wierność przewidywań modelu do rzeczywistych wyników. W tym rozdziale skupiono się na funkcjach, które można wykorzystać do pomiaru siły predykcji. Jednakże naszą radą dla osób opracowujących modele inferencyjne jest stosowanie tych technik nawet wtedy, gdy model nie będzie używany z głównym celem przewidywania.

Od dawna problemem w praktyce statystyki inferencyjnej jest to, że skupiając się wyłącznie na wnioskowaniu, trudno jest ocenić wiarygodność modelu. Na przykład, rozważ dane dotyczące choroby Alzheimera z Craig-Schapiro i in. (2011), gdzie 333 pacjentów było badanych w celu określenia czynników wpływających na upośledzenie funkcji poznawczych. W analizie można uwzględnić znane czynniki ryzyka i zbudować model regresji logistycznej, w którym wynik jest binarny (upośledzony/nieupośledzony). Rozważmy predyktory wieku, płci i genotypu apolipoproteiny E. Ta ostatnia jest zmienną kategoryczną zawierającą sześć możliwych kombinacji trzech głównych wariantów tego genu. Wiadomym jest, że apolipoproteina E ma związek z demencją (Kim, Basak, i Holtzman 2009).

Powierzchowne, ale nierzadkie podejście do tej analizy polegałoby na dopasowaniu dużego modelu z głównymi efektami i interakcjami, a następnie zastosowaniu testów statystycznych w celu znalezienia minimalnego zestawu efektów modelu, które są statystycznie istotne na jakimś wcześniej zdefiniowanym poziomie. Jeśli użyto pełnego modelu z trzema czynnikami i ich dwu- i trójstronnymi interakcjami, wstępnym etapem byłoby przetestowanie interakcji przy użyciu sekwencyjnych testów ilorazu prawdopodobieństwa (Hosmer i Lemeshow 2000). Przejdźmy przez takie podejście dla przykładowych danych dotyczących choroby Alzheimera:

  • Porównując model ze wszystkimi interakcjami dwukierunkowymi z modelem z dodatkową interakcją trójkierunkową, testy ilorazu wiarygodności dają wartość \(p\) równą 0,888. Oznacza to, że nie ma dowodów na to, że cztery dodatkowe terminy modelu związane z interakcją trójkierunkową wyjaśniają wystarczająco dużo zmienności w danych, aby zachować je w modelu.
  • Następnie, dwukierunkowe interakcje są podobnie oceniane w stosunku do modelu bez interakcji. Wartość \(p\) wynosi tutaj 0,0382. Biorąc pod uwagę niewielki rozmiar próbki, byłoby rozsądnie stwierdzić, że istnieją dowody na to, że niektóre z 10 możliwych dwukierunkowych interakcji są ważne dla modelu.
  • Na tej podstawie wyciągnęlibyśmy pewne wnioski z uzyskanych wyników. Interakcje te byłyby szczególnie ważne do omówienia, ponieważ mogą one zapoczątkować interesujące fizjologiczne lub neurologiczne hipotezy, które należy dalej badać.

Chociaż jest to strategia uproszczona, jest ona powszechna zarówno w praktyce, jak i w literaturze. Jest to szczególnie częste, jeśli praktykujący ma ograniczone formalne wykształcenie w zakresie analizy danych.

Jedną z brakujących informacji w tym podejściu jest to, jak blisko model ten pasuje do rzeczywistych danych. Stosując metody resamplingu, omówione w rozdziale 10, możemy oszacować dokładność tego modelu na około 73,4%. Dokładność jest często słabą miarą wydajności modelu; używamy jej tutaj, ponieważ jest powszechnie rozumiana. Jeśli model ma 73,4% dokładności w stosunku do danych, to czy powinniśmy zaufać wnioskom, które produkuje? Moglibyśmy tak myśleć, dopóki nie zdamy sobie sprawy, że wskaźnik bazowy nieupośledzonych pacjentów w danych wynosi 72,7%. Oznacza to, że pomimo naszej analizy statystycznej, model dwuczynnikowy okazuje się być tylko o 0,8% lepszy od prostej heurystyki, która zawsze przewiduje, że pacjenci nie są upośledzeni, niezależnie od obserwowanych danych.