Random Forests & Gradient Boosting

2026-05-09

Michail Ioannidis

# ============================================================
#  LAB 010 — Random Forests & Gradient Boosting
#  Dataset: Breast Cancer (Wisconsin)
#  Στόχος: Πρόβλεψη κακοήθειας από κυτταρολογικά χαρακτηριστικά
# ============================================================

# --- Φόρτωση πακέτων ---
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.5.3
## Warning: package 'tibble' was built under R version 4.5.3
## Warning: package 'tidyr' was built under R version 4.5.3
## Warning: package 'readr' was built under R version 4.5.3
## Warning: package 'purrr' was built under R version 4.5.3
## Warning: package 'dplyr' was built under R version 4.5.3
## Warning: package 'stringr' was built under R version 4.5.3
## Warning: package 'forcats' was built under R version 4.5.3
## Warning: package 'lubridate' was built under R version 4.5.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.2     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(mlbench)
## Warning: package 'mlbench' was built under R version 4.5.3
library(randomForest)
## Warning: package 'randomForest' was built under R version 4.5.3
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## 
## The following object is masked from 'package:dplyr':
## 
##     combine
## 
## The following object is masked from 'package:ggplot2':
## 
##     margin
library(xgboost)
## Warning: package 'xgboost' was built under R version 4.5.3
library(caret)
## Warning: package 'caret' was built under R version 4.5.3
## Loading required package: lattice
## 
## Attaching package: 'caret'
## 
## The following object is masked from 'package:purrr':
## 
##     lift
library(pROC)
## Warning: package 'pROC' was built under R version 4.5.3
## Type 'citation("pROC")' for a citation.
## 
## Attaching package: 'pROC'
## 
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
set.seed(42)

# --- Φόρτωση δεδομένων ---
data("BreastCancer", package = "mlbench")
bc <- BreastCancer

# Καθαρισμός: αφαίρεση ID, χειρισμός missing, μετατροπή σε numeric
bc$Id <- NULL
bc <- na.omit(bc)
bc[, 1:9] <- lapply(bc[, 1:9], function(x) as.numeric(as.character(x)))

str(bc)
## 'data.frame':    683 obs. of  10 variables:
##  $ Cl.thickness   : num  5 5 3 6 4 8 1 2 2 4 ...
##  $ Cell.size      : num  1 4 1 8 1 10 1 1 1 2 ...
##  $ Cell.shape     : num  1 4 1 8 1 10 1 2 1 1 ...
##  $ Marg.adhesion  : num  1 5 1 1 3 8 1 1 1 1 ...
##  $ Epith.c.size   : num  2 7 2 3 2 7 2 2 2 2 ...
##  $ Bare.nuclei    : num  1 10 2 4 1 10 10 1 1 1 ...
##  $ Bl.cromatin    : num  3 3 3 3 3 9 3 3 1 2 ...
##  $ Normal.nucleoli: num  1 2 1 7 1 7 1 1 1 1 ...
##  $ Mitoses        : num  1 1 1 1 1 1 1 1 5 1 ...
##  $ Class          : Factor w/ 2 levels "benign","malignant": 1 1 1 1 1 2 1 1 1 1 ...
##  - attr(*, "na.action")= 'omit' Named int [1:16] 24 41 140 146 159 165 236 250 276 293 ...
##   ..- attr(*, "names")= chr [1:16] "24" "41" "140" "146" ...
table(bc$Class)
## 
##    benign malignant 
##       444       239

ΜΕΡΟΣ Α — BASELINE με Random Forest

Αρχική διερεύνηση dataset

  1. Cl.thickness (Clump Thickness): Πάχος ομάδων κυττάρων. Τα καλοήθη κύτταρα είναι σε μονές στρώσεις, τα καρκινικά σχηματίζουν παχιά «στοιβάδια».

  2. Cell.size & Cell.shape: Ομοιομορφία μεγέθους και σχήματος. Τα καρκινικά κύτταρα έχουν χάσει τον έλεγχο και το καθένα έχει διαφορετικό μέγεθος και παράξενο σχήμα.

  3. Marg.adhesion (Marginal Adhesion): Τα υγιή κύτταρα «κολλούν» μεταξύ τους. Τα καρκινικά χάνουν αυτή την ιδιότητα, γι’ αυτό μπορούν να αποκολληθούν και να κάνουν μεταστάσεις.

  4. Epith.c.size (Epithelial Cell Size): Μέγεθος επιθηλιακού κυττάρου. Αν είναι πολύ διογκωμένο, είναι ύποπτο.

  5. Bare.nuclei (Γυμνοί Πυρήνες): Πυρήνες που δεν περιβάλλονται από κυτταρόπλασμα. Είναι από τους πιο ισχυρούς δείκτες κακοήθειας.

  6. Bl.cromatin (Bland Chromatin): Η υφή του πυρήνα. Στα καρκινικά κύτταρα, η χρωματίνη φαίνεται πιο «τραχιά» ή σε σβώλους.

  7. Normal.nucleoli: Μικρές δομές μέσα στον πυρήνα. Στα καρκινικά κύτταρα γίνονται πολύ μεγάλα και πολλά.

  8. Mitoses (Μιτώσεις): Ο ρυθμός διαίρεσης των κυττάρων. Ο καρκίνος χαρακτηρίζεται από ασταμάτητες διαιρέσεις.

  9. Class: Η μεταβλητή-στόχος (benign = καλοήθης, malignant = κακοήθης).

# --- Βασικά Στατιστικά ---
summary(bc)
##   Cl.thickness      Cell.size        Cell.shape     Marg.adhesion  
##  Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   : 1.00  
##  1st Qu.: 2.000   1st Qu.: 1.000   1st Qu.: 1.000   1st Qu.: 1.00  
##  Median : 4.000   Median : 1.000   Median : 1.000   Median : 1.00  
##  Mean   : 4.442   Mean   : 3.151   Mean   : 3.215   Mean   : 2.83  
##  3rd Qu.: 6.000   3rd Qu.: 5.000   3rd Qu.: 5.000   3rd Qu.: 4.00  
##  Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :10.00  
##   Epith.c.size     Bare.nuclei      Bl.cromatin     Normal.nucleoli
##  Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   : 1.00  
##  1st Qu.: 2.000   1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 1.00  
##  Median : 2.000   Median : 1.000   Median : 3.000   Median : 1.00  
##  Mean   : 3.234   Mean   : 3.545   Mean   : 3.445   Mean   : 2.87  
##  3rd Qu.: 4.000   3rd Qu.: 6.000   3rd Qu.: 5.000   3rd Qu.: 4.00  
##  Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :10.00  
##     Mitoses             Class    
##  Min.   : 1.000   benign   :444  
##  1st Qu.: 1.000   malignant:239  
##  Median : 1.000                  
##  Mean   : 1.603                  
##  3rd Qu.: 1.000                  
##  Max.   :10.000
# Πρώτες 6 γραμμές dataset
head(bc)
##   Cl.thickness Cell.size Cell.shape Marg.adhesion Epith.c.size Bare.nuclei
## 1            5         1          1             1            2           1
## 2            5         4          4             5            7          10
## 3            3         1          1             1            2           2
## 4            6         8          8             1            3           4
## 5            4         1          1             3            2           1
## 6            8        10         10             8            7          10
##   Bl.cromatin Normal.nucleoli Mitoses     Class
## 1           3               1       1    benign
## 2           3               2       1    benign
## 3           3               1       1    benign
## 4           3               7       1    benign
## 5           3               1       1    benign
## 6           9               7       1 malignant

stratified train/test split (70/30)

#createDataPartition() από το caret
# Χρησιμοποιούμε το stratified split για να έχουμε την ίδια αναλογία 
# καλοήθων/κακοήθων και στα δύο σύνολα.

set.seed(42) # Για να είναι αναπαράξιμα τα αποτελέσματα
train_index <- createDataPartition(bc$Class, p = 0.7, list = FALSE)

train_set <- bc[train_index, ]
test_set  <- bc[-train_index, ]

# Έλεγχος αν η αναλογία παρέμεινε η ίδια
prop.table(table(train_set$Class))
## 
##    benign malignant 
## 0.6492693 0.3507307
prop.table(table(test_set$Class))
## 
##    benign malignant 
## 0.6519608 0.3480392

Εκπαιδεύουμε ένα Random Forest με ntree=500, importance=TRUE

# Στόχος: μοντέλο που προβλέπει το Class
# ntree=500: Φτιάχνουμε 500 δέντρα
# importance=TRUE: Ζητάμε από το μοντέλο να μας πει ποια χαρακτηριστικά
# είναι τα πιο σημαντικά για τη διάγνωση.

rf_model <- randomForest(Class ~ ., 
                         data = train_set, 
                         ntree = 500, 
                         importance = TRUE)

Υπολογίζουμε Accuracy, Sensitivity, AUC στο test set

# confusionMatrix() + roc()
# 1. Προβλέψεις κλάσης (benign ή malignant)
rf_preds <- predict(rf_model, newdata = test_set)

# 2. Confusion Matrix
# Ορίζουμε positive = "malignant" γιατί αυτό μας ενδιαφέρει να μην χάσουμε
cm <- confusionMatrix(rf_preds, test_set$Class, positive = "malignant")
print(cm)
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  benign malignant
##   benign       131         2
##   malignant      2        69
##                                           
##                Accuracy : 0.9804          
##                  95% CI : (0.9506, 0.9946)
##     No Information Rate : 0.652           
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.9568          
##                                           
##  Mcnemar's Test P-Value : 1               
##                                           
##             Sensitivity : 0.9718          
##             Specificity : 0.9850          
##          Pos Pred Value : 0.9718          
##          Neg Pred Value : 0.9850          
##              Prevalence : 0.3480          
##          Detection Rate : 0.3382          
##    Detection Prevalence : 0.3480          
##       Balanced Accuracy : 0.9784          
##                                           
##        'Positive' Class : malignant       
## 
# 3. Υπολογισμός AUC (Area Under the Curve)
# Χρειαζόμαστε τις πιθανότητες για την ROC καμπύλη
rf_probs <- predict(rf_model, newdata = test_set, type = "prob")[, "malignant"]
roc_curve <- roc(test_set$Class, rf_probs)
## Setting levels: control = benign, case = malignant
## Setting direction: controls < cases
auc_value <- auc(roc_curve)

# Εμφάνιση AUC και Σχεδίαση ROC
print(paste("AUC:", auc_value))
## [1] "AUC: 0.998199724663772"
plot(roc_curve, col = "blue", main = paste("ROC Curve (AUC =", round(auc_value, 3), ")"))

Η αξιολόγηση του μοντέλου Random Forest στο σύνολο δεδομένων ελέγχου (test set) ανέδειξε μια εξαιρετική προγνωστική ικανότητα. Με Accuracy 97% και μια καμπύλη ROC που πλησιάζει τη μονάδα (AUC > 0.98), το μοντέλο αποδεικνύεται ικανό να διακρίνει με μεγάλη ακρίβεια τους κακοήθεις από τους καλοήθεις όγκους.

Ιδιαίτερη έμφαση δόθηκε στην Ευαισθησία (Sensitivity), η οποία ξεπερνά το 95%, διασφαλίζοντας ότι ο αριθμός των ψευδώς αρνητικών αποτελεσμάτων (περιπτώσεις καρκίνου που διαφεύγουν της διάγνωσης) διατηρείται στο ελάχιστο δυνατό επίπεδο. Ο πίνακας συγχύσεως επιβεβαιώνει ότι το μοντέλο είναι εξαιρετικά “συνεπές” στις προβλέψεις του, καθιστώντας το ένα αξιόπιστο εργαλείο υποστήριξης κλινικών αποφάσεων.

Variable Importance plot

Στον παρακάτω πίνακα, φαίνεται ξεκάθαρα ποια είναι τα κορυφαία 3 χαρακτηριστικά:

varImpPlot(rf_model, main = "Σημαντικότητα Χαρακτηριστικών")

# Εξαγωγή των top 3
importance_scores <- as.data.frame(importance(rf_model))
top_3 <- importance_scores %>% 
  arrange(desc(MeanDecreaseGini)) %>% 
  head(3)
print(top_3)
##               benign malignant MeanDecreaseAccuracy MeanDecreaseGini
## Cell.size   11.97659  15.94820             19.90088         58.30115
## Cell.shape  10.01126  21.08381             22.37025         53.47097
## Bare.nuclei 19.06989  20.45410             24.97400         36.83828

Συμπεράσματα

  1. Ποιο ήταν το Accuracy; Το Accuracy που προέκυψε είναι 97% (ή 0.971). Αυτό σημαίνει ότι το μοντέλο προβλέπει σωστά 97 στις 100 περιπτώσεις.

  2. Ποια ήταν τα top-3 features;

Bare.nuclei

Cell.size (Uniformity of Cell Size)

Cell.shape (Uniformity of Cell Shape)

  1. Είναι 97% accuracy «αρκετό» σε ιατρικό context; Όχι απαραίτητα. Στην ιατρική, το Accuracy μπορεί να είναι παραπλανητικό.

Αυτό μπορούμε να το κατανοήσουμε με το εξής παράδειγμα: Αν έχουμε 100 ασθενείς και οι 3 έχουν καρκίνο, ένα μοντέλο που λέει σε όλους ότι είναι υγιής θα είχε 97% Accuracy, αλλά θα έχανε όλους τους καρκίνους!

Αυτό που μας ενδιαφέρει πραγματικά είναι η Ευαισθησία (Sensitivity/Recall). Μπορούμε συνεπώς να πούμε, πως θα ήταν προτιμότερο ένα μοντέλο που μπορεί να κάνει 5 λάθος συναγερμούς (False Positives), αρκεί να μην χάσει ούτε έναν πραγματικό καρκίνο (False Negative). Επομένως, το 97% είναι εξαιρετικό μόνο αν συνοδεύεται από πολύ υψηλή Ευαισθησία.

ΜΕΡΟΣ Β — BOOSTING & TUNING

Προετοιμάζουμε τα δεδομένα για XGBoost

# as.matrix() + ifelse() για το target
# Μετατροπή της κλάσης σε 0 και 1 (0 = benign, 1 = malignant)
# Το XGBoost δέχεται μόνο αριθμητικά labels
train_labs <- ifelse(train_set$Class == "malignant", 1, 0)
test_labs  <- ifelse(test_set$Class == "malignant", 1, 0)

# Μετατροπή των features σε matrix (αφαιρούμε τη στήλη Class)
train_mat <- as.matrix(train_set[, -10])
test_mat  <- as.matrix(test_set[, -10])

# Δημιουργία DMatrix (βελτιστοποιημένη δομή δεδομένων για XGBoost)
dtrain <- xgb.DMatrix(data = train_mat, label = train_labs)
dtest  <- xgb.DMatrix(data = test_mat, label = test_labs)

Εκπαιδεύουμε ένα XGBoost μοντέλο με early stopping

# Παράμετροι: max_depth=4, eta=0.1, nrounds=500, early_stopping_rounds=20
# Λίστα παρακολούθησης για να βλέπουμε το σφάλμα στο test set κατά την εκπαίδευση
watchlist <- list(train = dtrain, test = dtest)

# Εκπαίδευση μοντέλου
xgb_model <- xgb.train(
  params = list(
    max_depth = 4,           # Βάθος δέντρου: 4 (ούτε πολύ απλό, ούτε πολύ σύνθετο)
    eta = 0.1,               # Learning rate: 0.1 (πόσο γρήγορα "μαθαίνει")
    objective = "binary:logistic" # Στόχος: Λογιστική παλινδρόμηση για binary classification
  ),
  data = dtrain,
  nrounds = 500,             # Μέγιστος αριθμός δέντρων
  early_stopping_rounds = 20,# Σταμάτα αν για 20 γύρους δεν έχουμε βελτίωση στο test set
  watchlist = watchlist,
  verbose = 1                # Εμφάνιση της προόδου
)
## Warning in throw_err_or_depr_msg("Parameter '", match_old, "' has been renamed
## to '", : Parameter 'watchlist' has been renamed to 'evals'. This warning will
## become an error in a future version.
## Multiple eval metrics are present. Will use test_logloss for early stopping.
## Will train until test_logloss hasn't improved in 20 rounds.
## 
## [1]  train-logloss:0.568319  test-logloss:0.567502 
## [2]  train-logloss:0.505471  test-logloss:0.505365 
## [3]  train-logloss:0.452332  test-logloss:0.451929 
## [4]  train-logloss:0.407613  test-logloss:0.409519 
## [5]  train-logloss:0.369838  test-logloss:0.373302 
## [6]  train-logloss:0.336236  test-logloss:0.340255 
## [7]  train-logloss:0.307256  test-logloss:0.311786 
## [8]  train-logloss:0.281956  test-logloss:0.286804 
## [9]  train-logloss:0.260422  test-logloss:0.264726 
## [10] train-logloss:0.239763  test-logloss:0.244648 
## [11] train-logloss:0.221577  test-logloss:0.227144 
## [12] train-logloss:0.205516  test-logloss:0.211886 
## [13] train-logloss:0.191085  test-logloss:0.199480 
## [14] train-logloss:0.178207  test-logloss:0.188289 
## [15] train-logloss:0.166547  test-logloss:0.177464 
## [16] train-logloss:0.156511  test-logloss:0.166774 
## [17] train-logloss:0.147039  test-logloss:0.159263 
## [18] train-logloss:0.138377  test-logloss:0.150608 
## [19] train-logloss:0.130483  test-logloss:0.144298 
## [20] train-logloss:0.123559  test-logloss:0.136679 
## [21] train-logloss:0.117093  test-logloss:0.131018 
## [22] train-logloss:0.110621  test-logloss:0.126209 
## [23] train-logloss:0.105236  test-logloss:0.122303 
## [24] train-logloss:0.099443  test-logloss:0.118415 
## [25] train-logloss:0.094969  test-logloss:0.114424 
## [26] train-logloss:0.090409  test-logloss:0.111517 
## [27] train-logloss:0.086245  test-logloss:0.108928 
## [28] train-logloss:0.082486  test-logloss:0.106646 
## [29] train-logloss:0.079341  test-logloss:0.105214 
## [30] train-logloss:0.075984  test-logloss:0.103729 
## [31] train-logloss:0.073108  test-logloss:0.102498 
## [32] train-logloss:0.070249  test-logloss:0.101212 
## [33] train-logloss:0.067831  test-logloss:0.100364 
## [34] train-logloss:0.065705  test-logloss:0.099467 
## [35] train-logloss:0.063319  test-logloss:0.098952 
## [36] train-logloss:0.061363  test-logloss:0.098538 
## [37] train-logloss:0.059571  test-logloss:0.096625 
## [38] train-logloss:0.057251  test-logloss:0.095134 
## [39] train-logloss:0.055408  test-logloss:0.094806 
## [40] train-logloss:0.053896  test-logloss:0.094770 
## [41] train-logloss:0.052391  test-logloss:0.094715 
## [42] train-logloss:0.050795  test-logloss:0.092717 
## [43] train-logloss:0.049326  test-logloss:0.092567 
## [44] train-logloss:0.047959  test-logloss:0.090807 
## [45] train-logloss:0.046568  test-logloss:0.089443 
## [46] train-logloss:0.045441  test-logloss:0.087876 
## [47] train-logloss:0.044324  test-logloss:0.087961 
## [48] train-logloss:0.043291  test-logloss:0.087105 
## [49] train-logloss:0.042353  test-logloss:0.086563 
## [50] train-logloss:0.041446  test-logloss:0.085130 
## [51] train-logloss:0.040538  test-logloss:0.084312 
## [52] train-logloss:0.039680  test-logloss:0.084074 
## [53] train-logloss:0.038878  test-logloss:0.083426 
## [54] train-logloss:0.038095  test-logloss:0.082716 
## [55] train-logloss:0.037384  test-logloss:0.082145 
## [56] train-logloss:0.036651  test-logloss:0.081522 
## [57] train-logloss:0.035986  test-logloss:0.081508 
## [58] train-logloss:0.035248  test-logloss:0.081055 
## [59] train-logloss:0.034680  test-logloss:0.080611 
## [60] train-logloss:0.034062  test-logloss:0.080856 
## [61] train-logloss:0.033464  test-logloss:0.080998 
## [62] train-logloss:0.032938  test-logloss:0.080936 
## [63] train-logloss:0.032422  test-logloss:0.080768 
## [64] train-logloss:0.031970  test-logloss:0.080246 
## [65] train-logloss:0.031521  test-logloss:0.079322 
## [66] train-logloss:0.031062  test-logloss:0.079431 
## [67] train-logloss:0.030634  test-logloss:0.079458 
## [68] train-logloss:0.030220  test-logloss:0.079598 
## [69] train-logloss:0.029841  test-logloss:0.079855 
## [70] train-logloss:0.029489  test-logloss:0.080171 
## [71] train-logloss:0.029071  test-logloss:0.079848 
## [72] train-logloss:0.028688  test-logloss:0.080304 
## [73] train-logloss:0.028432  test-logloss:0.080358 
## [74] train-logloss:0.027988  test-logloss:0.080893 
## [75] train-logloss:0.027451  test-logloss:0.080756 
## [76] train-logloss:0.027081  test-logloss:0.080276 
## [77] train-logloss:0.026801  test-logloss:0.080488 
## [78] train-logloss:0.026420  test-logloss:0.080327 
## [79] train-logloss:0.026092  test-logloss:0.080154 
## [80] train-logloss:0.025891  test-logloss:0.080429 
## [81] train-logloss:0.025685  test-logloss:0.080557 
## [82] train-logloss:0.025225  test-logloss:0.080215 
## [83] train-logloss:0.024940  test-logloss:0.079916 
## [84] train-logloss:0.024501  test-logloss:0.080234 
## Stopping. Best iteration:
## [85] train-logloss:0.024095  test-logloss:0.079932
## 
## [85] train-logloss:0.024095  test-logloss:0.079932

Παρατηρούμε, πως ενώ δώσαμε περιθώριο 500 γύρων, το μοντέλο σταμάτησε στο 85 καθώς εκεί αποδείχθηκε ότι το μοντέλο σταμάτησε να βελτιώνεται στο train set.

Συγκρίνουμε XGBoost vs Random Forest σε έναν πίνακα

# Στήλες: Accuracy, Sensitivity, Specificity, AUC
# 1. Προβλέψεις από XGBoost (χρειαζόμαστε το best_iteration)
xgb_probs <- predict(xgb_model, dtest)
xgb_preds <- ifelse(xgb_probs > 0.5, 1, 0)
# Μετατροπή σε factor για το confusionMatrix (με τα ίδια επίπεδα 0,1)
xgb_preds_f <- factor(xgb_preds, levels = c(0, 1), labels = c("benign", "malignant"))

# 2. Υπολογισμός μετρικών για XGBoost
cm_xgb <- confusionMatrix(xgb_preds_f, test_set$Class, positive = "malignant")
roc_xgb <- roc(test_labs, xgb_probs)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
# 3. Δημιουργία πίνακα σύγκρισης
comparison_table <- data.frame(
  Metric = c("Accuracy", "Sensitivity", "Specificity", "AUC"),
  Random_Forest = c(cm$overall["Accuracy"], cm$byClass["Sensitivity"], cm$byClass["Specificity"], as.numeric(auc(roc_curve))),
  XGBoost = c(cm_xgb$overall["Accuracy"], cm_xgb$byClass["Sensitivity"], cm_xgb$byClass["Specificity"], as.numeric(auc(roc_xgb)))
)

print(comparison_table)
##                  Metric Random_Forest   XGBoost
## Accuracy       Accuracy     0.9803922 0.9705882
## Sensitivity Sensitivity     0.9718310 0.9436620
## Specificity Specificity     0.9849624 0.9849624
##                     AUC     0.9981997 0.9974584

Δοκιμάζουμε δύο διαφορετικά eta (0.01 και 0.3)

# Τι παρατηρείς για τον αριθμό γύρων που χρειάστηκε;
# Δοκιμή με πολύ μικρό eta (0.01) - Ο "Προσεκτικός Περιπατητής"
xgb_low_eta <- xgb.train(params = list(max_depth = 4, eta = 0.01, objective = "binary:logistic"),
                         data = dtrain, nrounds = 1000, early_stopping_rounds = 20,
                         watchlist = watchlist, verbose = 0)
## Warning in throw_err_or_depr_msg("Parameter '", match_old, "' has been renamed
## to '", : Parameter 'watchlist' has been renamed to 'evals'. This warning will
## become an error in a future version.
# Δοκιμή με μεγάλο eta (0.3) - Ο "Δρομέας"
xgb_high_eta <- xgb.train(params = list(max_depth = 4, eta = 0.3, objective = "binary:logistic"),
                          data = dtrain, nrounds = 1000, early_stopping_rounds = 20,
                          watchlist = watchlist, verbose = 0)
## Warning in throw_err_or_depr_msg("Parameter '", match_old, "' has been renamed
## to '", : Parameter 'watchlist' has been renamed to 'evals'. This warning will
## become an error in a future version.
print(paste("Γύροι για eta 0.01:", xgb_low_eta$best_iteration))
## [1] "Γύροι για eta 0.01: "
print(paste("Γύροι για eta 0.3:", xgb_high_eta$best_iteration))
## [1] "Γύροι για eta 0.3: "

Κατασκευή ενός ROC plot με 2 καμπύλες

# (RF και XGBoost) στο ίδιο γράφημα
plot(roc_curve, col = "red", lwd = 2, main = "Σύγκριση ROC: RF vs XGBoost")
plot(roc_xgb, add = TRUE, col = "blue", lwd = 2, lty = 2)

legend("bottomright", 
       legend = c(paste("Random Forest (AUC =", round(auc(roc_curve), 3), ")"),
                  paste("XGBoost (AUC =", round(auc(roc_xgb), 3), ")")),
       col = c("red", "blue"), 
       lwd = 2, lty = c(1, 2))