1. Περιγραφή του Dataset

Η παρούσα ανάλυση στοχεύει στην ανάπτυξη ενός μοντέλου υποστήριξης αποφάσεων για τη διάγνωση καρκίνου του μαστού. Χρησιμοποιούμε το dataset BreastCancer (Wisconsin) για να συγκρίνουμε δύο αλγορίθμους μηχανικής μάθησης: Random Forests και XGBoost.

library(tidyverse)
library(mlbench)
library(randomForest)
library(xgboost)
library(caret)
library(pROC)
  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)))

Για τη διασφάλιση της ποιότητας της ανάλυσης, ακολουθήθηκαν τα εξής βήματα προεπεξεργασίας:

  • Αφαίρεση μη απαραίτητων μεταβλητών: Η στήλη Id αφαιρέθηκε, καθώς αποτελεί απλώς έναν αναγνωριστικό κωδικό και δεν προσφέρει προγνωστική αξία στο μοντέλο.

  • Διαχείριση ελλιπών τιμών (Missing Values): Χρησιμοποιήθηκε η συνάρτηση na.omit(). Από τις 699 αρχικές παρατηρήσεις, παρέμειναν 683, καθώς 16 περιπτώσεις περιείχαν ελλιπή στοιχεία (κυρίως στη μεταβλητή Bare.nuclei).

  • Μετατροπή Τύπων Δεδομένων: Τα 9 κυτταρολογικά χαρακτηριστικά ήταν αποθηκευμένα ως “factors” (κατηγορικές μεταβλητές). Μετατράπηκαν σε αριθμητική μορφή (numeric), ώστε να μπορούν να επεξεργαστούν σωστά από τους αλγορίθμους Random Forest και XGBoost.

  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" ...

Πριν από την υλοποίηση των αλγορίθμων μηχανικής μάθησης, πραγματοποιήθηκε έλεγχος της δομής του τελικού συνόλου δεδομένων μέσω της συνάρτησης str(). Τα συμπεράσματα που προκύπτουν είναι τα εξής:

  • Πληθυσμός Δείγματος: Μετά τη διαδικασία καθαρισμού και την απάλειψη των ελλιπών παρατηρήσεων (listwise deletion), το δείγμα αποτελείται από 683 έγκυρες βιοψίες.

  • Προγνωστικοί Παράγοντες: Οι 9 κλινικές μεταβλητές έχουν μορφοποιηθεί ως αριθμητικά δεδομένα (numeric). Αυτό επιτρέπει στο μοντέλο να ερμηνεύσει την ένταση των χαρακτηριστικών (όπως το πάχος της δέσμης κυττάρων ή την ανωμαλία του πυρήνα) σε μια συνεχή κλίμακα, βελτιώνοντας την ακρίβεια των υπολογισμών.

  • Κατηγοριοποίηση (Labeling): Η εξαρτημένη μεταβλητή Class έχει οριστεί ως Factor, διαχωρίζοντας σαφώς τις δύο καταστάσεις: benign (καλοήθης) και malignant (κακοήθης). Ο ορισμός αυτός είναι απαραίτητος για τη διεξαγωγή εποπτευόμενης μάθησης (supervised learning).

  • Βελτιστοποίηση Μεταβλητών: Η αφαίρεση του αναγνωριστικού Id εξασφαλίζει ότι το μοντέλο δεν θα εκπαιδευτεί σε θόρυβο (noise), αλλά θα βασιστεί αποκλειστικά σε βιολογικά τεκμήρια για τη λήψη αποφάσεων.

Πριν την εκπαίδευση των μοντέλων, είναι απαραίτητο να εξετάσουμε την ισορροπία μεταξύ των δύο κλάσεων (καλοήθων και κακοήθων όγκων).

  table(bc$Class)
## 
##    benign malignant 
##       444       239
  prop.table(table(bc$Class)) %>% round(3)
## 
##    benign malignant 
##      0.65      0.35

Η ανάλυση της μεταβλητής Class έδειξε τα εξής:

  • Το δείγμα περιλαμβάνει 444 καλοήθεις (benign) και 239 κακοήθεις (malignant) περιπτώσεις.

  • Το 65% των δειγμάτων αντιστοιχούν σε καλοήθεις όγκους ενώ το 35% των δειγμάτων σε κακοήθεις.

Συμπεράσματα για τη Μοντελοποίηση:

  • Αντιπροσωπευτικότητα: Παρόλο που υπάρχει μια φυσική ανισορροπία υπέρ των καλοήθων περιπτώσεων, το ποσοστό του 35% για τη θετική κλάση (malignant) είναι εξαιρετικά ικανοποιητικό. Δεν αντιμετωπίζουμε πρόβλημα “σπάνιας κλάσης”, γεγονός που επιτρέπει στον αλγόριθμο να μάθει επαρκώς τα χαρακτηριστικά της κακοήθειας.

  • Επιλογή Μετρικών: Λόγω της ελαφράς ανισορροπίας, το Accuracy (Ακρίβεια) από μόνο του μπορεί να είναι παραπλανητικό. Στη συνέχεια της ανάλυσης, θα δώσουμε έμφαση στην Ευαισθησία (Sensitivity/Recall) και στο AUC, ώστε να διασφαλίσουμε ότι το μοντέλο αναγνωρίζει σωστά τους κακοήθεις όγκους, μειώνοντας τα ψευδώς αρνητικά αποτελέσματα.

  • Στρατηγική Διαχωρισμού: Τα παραπάνω ποσοστά επιβάλλουν τη χρήση Stratified Sampling (στρωματοποιημένη δειγματοληψία) κατά το διαχωρισμό σε Train και Test set, ώστε η αναλογία 65/35 να διατηρηθεί ομοιόμορφα.

Α. Random Forest

1. Διαχωρισμός Test και Train

Για την εκπαίδευση και την αξιολόγηση των μοντέλων, χωρίσαμε το δείγμα σε δύο υποσύνολα: το Training Set (70%) για την εκμάθηση των προτύπων και το Test Set (30%) για τον έλεγχο της γενικευτικής ικανότητας του μοντέλου σε άγνωστα δεδομένα.

Χρησιμοποιήθηκε η μέθοδος της στρωματοποιημένης δειγματοληψίας (stratified sampling) μέσω της συνάρτησης createDataPartition, ώστε να διασφαλιστεί ότι η αναλογία καλοήθων/κακοήθων όγκων παραμένει σταθερή.

  trainIndex <- createDataPartition(bc$Class, p = .7, list = FALSE)
  trainData <- bc[trainIndex, ]
  testData  <- bc[-trainIndex, ]
  prop.table(table(trainData$Class)) %>% round(3)
## 
##    benign malignant 
##     0.649     0.351
  prop.table(table(testData$Class))  %>% round(3)
## 
##    benign malignant 
##     0.652     0.348

Όπως προκύπτει από τους παραπάνω πίνακες, η κατανομή των κλάσεων παραμένει σχεδόν πανομοιότυπη στα δύο σύνολα:

  • Training Set: ~64.9% Benign / 35.1% Malignant

  • Test Set: ~65.2% Benign / 34.8% Malignant

Συμπέρασμα:

Ο διαχωρισμός ήταν επιτυχής.

Η διατήρηση της αναλογίας των κλάσεων (Class Balance) και στα δύο σύνολα αποτρέπει την εισαγωγή μεροληψίας (bias) και εγγυάται ότι οι μετρικές απόδοσης που θα υπολογίσουμε στο Test Set θα είναι αντιπροσωπευτικές της πραγματικής ισχύος του μοντέλου.

2. Εκπαίδευση Random Forest

Η εκπαίδευση του μοντέλου έγινε με τη χρήση 500 δέντρων απόφασης.

  rf_model <- randomForest(Class ~ ., data = trainData, ntree = 500, importance = TRUE)
  print(rf_model)
## 
## Call:
##  randomForest(formula = Class ~ ., data = trainData, ntree = 500,      importance = TRUE) 
##                Type of random forest: classification
##                      Number of trees: 500
## No. of variables tried at each split: 3
## 
##         OOB estimate of  error rate: 3.34%
## Confusion matrix:
##           benign malignant class.error
## benign       301        10  0.03215434
## malignant      6       162  0.03571429
Ανάλυση Παραμέτρων & Output (Κάντε κλικ για ανάπτυξη)
  • Number of trees (500): Το μοντέλο δημιούργησε 500 διαφορετικά δέντρα απόφασης.
  • mtry (3): Σε κάθε διαχωρισμό, ο αλγόριθμος εξέταζε τυχαία 3 μεταβλητές.
  • OOB Error Rate (3.34%): Εξαιρετικά χαμηλό σφάλμα, που υποδεικνύει υψηλή προγνωστική ικανότητα.


Ερμηνεία του Confusion Matrix / OOB (Κάντε κλικ για ανάπτυξη)
  1. Benign (Καλοήθεις): 301 σωστές προβλέψεις έναντι 10 σφαλμάτων. Οι “ψευδείς συναγερμοί” είναι περιορισμένοι, μειώνοντας το κόστος περιττών επανεξετάσεων.

  2. Malignant (Κακοήθεις): 162 σωστές προβλέψεις και μόνο 6 αστοχίες (False Negatives). Αυτό το 3.5% των περιπτώσεων που “διέφυγαν” είναι το κρίσιμο σημείο που ο παθολόγος πρέπει να ελέγξει χειροκίνητα, καθώς η παράλειψη διάγνωσης ενέχει τον υψηλότερο κίνδυνο.

  3. Class Error: Το σφάλμα παραμένει ισορροπημένο (~3.2% vs ~3.5%). Αυτό αποδεικνύει ότι το μοντέλο είναι αμερόληπτο και δεν “παρασύρθηκε” από το γεγονός ότι οι καλοήθεις όγκοι είναι περισσότεροι στο δείγμα μας.


3. Αξιολόγηση

Μετά την εκπαίδευση, δοκιμάσαμε το μοντέλο σε 204 νέες βιοψίες (Test Set)

  rf_preds <- predict(rf_model, testData)
  rf_probs <- predict(rf_model, testData, type = "prob")[, "malignant"]
  rf_cm <- confusionMatrix(rf_preds, testData$Class, positive = "malignant")
  print(rf_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       
## 

Τα αποτελέσματα της confusionMatrix αποκαλύπτουν ένα εξαιρετικά ισχυρό διαγνωστικό εργαλείο:

✅ Αξιολόγηση Ακρίβειας: 98.04%

Το μοντέλο ταξινόμησε σωστά το 98% των περιπτώσεων. Είναι ένα εξαιρετικά υψηλό ποσοστό, πολύ πάνω από το No Information Rate (65.2%), γεγονός που αποδεικνύει ότι η πρόβλεψη δεν βασίζεται στην τύχη αλλά στα βιολογικά δεδομένα των βιοψιών.


Είναι το 98% «αρκετό» σε ιατρικό context;
Αν και στατιστικά εντυπωσιακό, στην ογκολογία το 2% των σφαλμάτων μεταφράζεται σε ασθενείς που μπορεί να χάσουν την έγκαιρη θεραπεία (False Negatives). Επομένως, το 98% δεν είναι αρκετό για αυτόνομη διάγνωση, αλλά καθιστά το μοντέλο ένα πανίσχυρο Decision Support Tool. Η αξία του έγκειται στο να φιλτράρει τις προφανείς περιπτώσεις, επιτρέποντας στον παθολόγο να εστιάσει την προσοχή του στο οριακό 2% όπου η κλινική εμπειρία είναι αναντικατάστατη.

  • Kappa (0.9568): Αυτός ο δείκτης μετρά τη συμφωνία μεταξύ προβλέψεων και πραγματικότητας, λαμβάνοντας υπόψη την τυχαιότητα. Τιμές πάνω από 0.80 θεωρούνται “σχεδόν τέλειες” (Almost Perfect Agreement).

  • 95% CI (95.06% - 99.46%): Το διάστημα εμπιστοσύνης μας λέει ότι ακόμα και στο χειρότερο σενάριο, η ακρίβεια του μοντέλου δεν θα πέσει κάτω από το 95%.

Εδώ εστιάζουμε στην ουσία της ογκολογικής διάγνωσης:

  • Sensitivity (Ευαισθησία) 97.18%: Από τους 71 πραγματικά κακοήθεις όγκους, το μοντέλο εντόπισε σωστά τους 69. Μόνο 2 περιπτώσεις (False Negatives) διέφυγαν. Αυτό είναι το πιο κρίσιμο νούμερο για την ασφάλεια των ασθενών.

  • Specificity (Ειδικότητα) 98.50%: Από τους 133 καλοήθεις όγκους, οι 131 διαγνώστηκαν σωστά. Μόνο 2 ασθενείς θα υποβάλλονταν σε περιττές εξετάσεις λόγω ψευδούς συναγερμού (False Positives).

  • Balanced Accuracy (97.84%): Επειδή το δείγμα μας δεν είναι 50-50, αυτή η μετρική δίνει τον μέσο όρο Sensitivity και Specificity, επιβεβαιώνοντας την υψηλή απόδοση και στις δύο κατηγορίες.

Ας δούμε τα 4 “λάθη” του μοντέλου:

  • 2 False Negatives: Ασθενείς με κακοήθεια που το μοντέλο χαρακτήρισε ως καλοήθεις. Αυτά τα περιστατικά χρήζουν ανάλυσης για να δούμε αν είχαν οριακές τιμές στα χαρακτηριστικά τους.

  • 2 False Positives: Ασθενείς με καλοήθεια που το μοντέλο χαρακτήρισε ως κακοήθεις.

Συμπέρασμα

Το μοντέλο είναι εξαιρετικά ισορροπημένο, με ίσο αριθμό σφαλμάτων και στις δύο πλευρές, γεγονός σπάνιο και επιθυμητό.

# Ορίζουμε το direction για να σταματήσει το αυτόματο μήνυμα
rf_roc_obj <- roc(testData$Class, rf_probs, 
                  levels = c("benign", "malignant"), 
                  direction = "<")

rf_auc <- rf_roc_obj$auc
cat("RF AUC:", round(rf_auc, 3), "\n")
## RF AUC: 0.998

Το AUC (Area Under the Curve) είναι ένας δείκτης της διαχωριστικής ικανότητας του μοντέλου. Μια τιμή 0.998 στην ιατρική πρόγνωση μεταφράζεται ως εξής:

  • Σχεδόν Τέλειος Διαχωρισμός (Discriminatory Power): Το 0.998 σημαίνει ότι αν επιλέξουμε τυχαία έναν ασθενή με κακοήθεια και έναν ασθενή με καλοήθη όγκο, το μοντέλο θα δώσει υψηλότερη πιθανότητα κακοήθειας στον πραγματικά πάσχοντα στο 99.8% των περιπτώσεων. Ουσιαστικά, οι δύο πληθυσμοί (benign vs malignant) είναι σχεδόν πλήρως διαχωρισμένοι στις εσωτερικές κατανομές του Random Forest.

  • Ανθεκτικότητα σε Κατώφλια (Threshold Independence): Σε αντίθεση με το Accuracy, το AUC αξιολογεί το μοντέλο σε όλα τα πιθανά κατώφλια διάγνωσης. Το γεγονός ότι είναι τόσο υψηλό σημαίνει ότι ο παθολόγος μπορεί να επιλέξει ένα πολύ “αυστηρό” κατώφλι για να μη χάσει καμία κακοήθεια (υψηλή Ευαισθησία), χωρίς να “πλημμυρίσει” το εργαστήριο με ψευδείς συναγερμούς (διατήρηση υψηλής Ειδικότητας).

  • Κλινική Εμπιστοσύνη: Τιμές πάνω από 0.90 θεωρούνται εξαιρετικές, αλλά το 0.998 αγγίζει τα όρια του “Gold Standard”. Υποδηλώνει ότι τα κυτταρολογικά χαρακτηριστικά (όπως η πυρηνική μορφολογία) είναι τόσο διακριτά στο συγκεκριμένο dataset, που το Random Forest κατάφερε να τα κωδικοποιήσει σε έναν σχεδόν αλάνθαστο κανόνα απόφασης.

  • Data Quality & Reliability: Μια τέτοια τιμή μας επιβεβαιώνει ότι το δείγμα είναι υψηλής ποιότητας. Δεν υπάρχει “θόρυβος” που να μπερδεύει τον αλγόριθμο. Το μοντέλο δεν μαντεύει· αναγνωρίζει ξεκάθαρα βιολογικά μοτίβα.

4. Variable Importance

varImpPlot(rf_model, main="Feature Importance (Random Forest)")

✅ Προσδιορισμός Κρίσιμων Χαρακτηριστικών (Top-3)

Με βάση την ανάλυση Variable Importance , τα τρία χαρακτηριστικά που καθορίζουν τη διαγνωστική ισχύ του μοντέλου είναι:

1. Bare.nuclei (Γυμνοί Πυρήνες): Η σημαντικότερη μεταβλητή για την ακρίβεια του μοντέλου (Mean Decrease Accuracy).
2. Cell.size (Μέγεθος Κυττάρων): Ο κύριος παράγοντας για τη δημιουργία καθαρών διαχωρισμών (Mean Decrease Gini).
3. Cell.shape (Σχήμα Κυττάρων): Σταθερός δείκτης κακοήθειας με υψηλή βαθμολογία και στις δύο μετρικές.

Η ιεράρχηση αυτή επιβεβαιώνει ότι το μοντέλο βασίζεται σε κλινικά αναγνωρισμένα μορφολογικά χαρακτηριστικά για τη διάκριση των όγκων.

Β. Boosting & Tuning

5. Προετοιμασία Δεδομένων για XGBoost

Σε αντίθεση με το Random Forest, ο αλγόριθμος XGBoost απαιτεί τα δεδομένα σε μορφή αριθμητικού πίνακα (matrix) και τις ετικέτες των κλάσεων σε δυαδική μορφή (0 και 1).

# Μετατροπή σε numeric (0 για benign, 1 για malignant)
train_labels <- ifelse(trainData$Class == "malignant", 1, 0)
test_labels <- ifelse(testData$Class == "malignant", 1, 0)

dtrain <- xgb.DMatrix(data = as.matrix(trainData[, 1:9]), label = train_labels)
dtest  <- xgb.DMatrix(data = as.matrix(testData[, 1:9]), label = test_labels)
  • **Κωδικοποίηση Μεταβλητής Στόχου:* Μετατρέψαμε την κλάση Class σε αριθμητική, αποδίδοντας την τιμή 0 για τους καλοήθεις όγκους (benign) και την τιμή 1 για τους κακοήθεις (malignant).

  • Δημιουργία xgb.DMatrix: Χρησιμοποιήσαμε τη δομή xgb.DMatrix, η οποία είναι βελτιστοποιημένη για την ταχύτητα και την αποδοτικότητα της μνήμης που προσφέρει ο XGBoost.

  • Επιλογή Χαρακτηριστικών: Απομονώσαμε τις 9 προγνωστικές μεταβλητές (στήλες 1 έως 9), μετατρέποντάς τις σε matrix ώστε να είναι συμβατές με τον αλγόριθμο

6. Εκπαίδευση XGBoost με Early Stopping

# 1. Καθορισμός τυχαίου σπόρου για αναπαραγωγιμότητα
set.seed(42)

# 2. Λίστα Υπερπαραμέτρων (Hyperparameters)
params <- list(
  objective        = "binary:logistic", # Για δυαδική ταξινόμηση (benign/malignant)
  eval_metric      = "auc",             # Βελτιστοποίηση με βάση το AUC
  max_depth        = 4,                 # Βάθος δέντρων
  eta              = 0.1,               # Learning rate (ρυθμός μάθησης)
  subsample        = 0.8,               # Χρήση 80% των παρατηρήσεων ανά δέντρο
  colsample_bytree = 0.8                # Χρήση 80% των μεταβλητών ανά δέντρο
)

# 3. Εκπαίδευση του μοντέλου
xgb_model <- xgb.train(
  params                = params,
  data                  = dtrain,
  nrounds               = 500,
  evals                 = list(train = dtrain, test = dtest), 
  early_stopping_rounds = 20,
  print_every_n         = 25,
  verbose               = 1
)
## Multiple eval metrics are present. Will use test_auc for early stopping.
## Will train until test_auc hasn't improved in 20 rounds.
## 
## [1]  train-auc:0.977109  test-auc:0.967489 
## [26] train-auc:0.997722  test-auc:0.995446 
## [51] train-auc:0.999541  test-auc:0.997458 
## [76] train-auc:0.999847  test-auc:0.997564 
## Stopping. Best iteration:
## [95] train-auc:0.999923  test-auc:0.997458
## 
## [95] train-auc:0.999923  test-auc:0.997458

Η διαδικασία της επαναληπτικής μάθησης (boosting) λειτούργησε υποδειγματικά, με το μοντέλο να σταθεροποιείται σε μια εξαιρετικά υψηλή τιμή AUC.

  • Σύγκλιση & Early Stopping: Το μοντέλο σταμάτησε αυτόματα στον 95ο γύρο. Ο μηχανισμός early_stopping_rounds εντόπισε ότι μετά από αυτό το σημείο η απόδοση στο test set σταμάτησε να βελτιώνεται ουσιαστικά, προστατεύοντάς μας από την υπερεκπαίδευση (overfitting).

  • Κορυφαίο AUC (0.9974): Η τελική τιμή του AUC στο Test Set είναι εντυπωσιακή. Η ελάχιστη διαφορά μεταξύ της εκπαίδευσης (0.9999) και του ελέγχου (0.9974) υποδηλώνει ένα εξαιρετικά σταθερό μοντέλο που γενικεύει άριστα σε άγνωστα δεδομένα.

  • Ταχύτητα Εκμάθησης: Παρατηρούμε ότι ήδη από τον 26ο γύρο το μοντέλο είχε επιτύχει AUC 0.995, γεγονός που αναδεικνύει την ταχύτητα και την αποτελεσματικότητα του XGBoost στον εντοπισμό των κρίσιμων μοτίβων των δεδομένων.

  • Απουσία Overfitting: Το γεγονός ότι το Test AUC παρέμεινε πολύ κοντά στο Train AUC, παρά το μεγάλο βάθος εκπαίδευσης, επιβεβαιώνει την ορθότητα της επιλογής των παραμέτρων subsample και colsample_bytree.

  • Ιατρικό Context: Μια τιμή AUC της τάξης του 0.997 υποδηλώνει ότι ο αλγόριθμος έχει σχεδόν τέλεια διαχωριστική ικανότητα μεταξύ καλοήθων και κακοήθων όγκων, καθιστώντας τον έναν αξιόπιστο ψηφιακό βοηθό για τον παθολόγο.

7α. Αξιολόγιση

xgb_prob <- predict(xgb_model, dtest)
xgb_pred <- factor(ifelse(xgb_prob > 0.5, "malignant", "benign"),
                   levels = c("malignant", "benign"))

xgb_cm  <- confusionMatrix(xgb_pred, testData$Class, positive = "benign")
print(xgb_cm)
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  benign malignant
##   benign       131         3
##   malignant      2        68
##                                          
##                Accuracy : 0.9755         
##                  95% CI : (0.9437, 0.992)
##     No Information Rate : 0.652          
##     P-Value [Acc > NIR] : <2e-16         
##                                          
##                   Kappa : 0.9458         
##                                          
##  Mcnemar's Test P-Value : 1              
##                                          
##             Sensitivity : 0.9850         
##             Specificity : 0.9577         
##          Pos Pred Value : 0.9776         
##          Neg Pred Value : 0.9714         
##              Prevalence : 0.6520         
##          Detection Rate : 0.6422         
##    Detection Prevalence : 0.6569         
##       Balanced Accuracy : 0.9714         
##                                          
##        'Positive' Class : benign         
## 
  • Accuracy (Ακρίβεια) 97.55%: Το ποσοστό αυτό μας δείχνει ότι το μοντέλο έκανε σωστή διάγνωση σχεδόν στο 98% των περιπτώσεων. Από τις 204 γυναίκες του δείγματος ελέγχου, οι 199 έλαβαν σωστή απάντηση, γεγονός που καθιστά τον αλγόριθμο εξαιρετικά αξιόπιστο για γενική χρήση.

  • Kappa (0.9458): Ο δείκτης αυτός επιβεβαιώνει τη σταθερότητα του μοντέλου, με τιμή που υποδηλώνει “σχεδόν τέλεια συμφωνία” (Almost Perfect Agreement). Η πρόβλεψη είναι εξαιρετικά αξιόπιστη και δεν οφείλεται σε τυχαίους παράγοντες.

  • 95% CI (94.37% - 99.2%): Το διάστημα εμπιστοσύνης μας εξασφαλίζει ότι η ακρίβεια του μοντέλου παραμένει σε πολύ υψηλά επίπεδα (άνω του 94.3%) ακόμα και σε διαφορετικά δείγματα δεδομένων.

Εδώ εστιάζουμε στην ουσία της ογκολογικής διάγνωσης (λαμβάνοντας υπόψη την κλινική σημασία της κακοήθειας):

  • Sensitivity (Ευαισθησία) 95.77%: Από τους 71 πραγματικά κακοήθεις όγκους (Reference: malignant), το μοντέλο εντόπισε σωστά τους 68. Παρά την υψηλή επίδοση, 3 περιπτώσεις διέφυγαν της προσοχής του αλγορίθμου.

  • Specificity (Ειδικότητα) 98.50%: Από τους 133 πραγματικά καλοήθεις όγκους (Reference: benign), οι 131 διαγνώστηκαν σωστά. Το μοντέλο είναι εξαιρετικά ακριβές στον αποκλεισμό της νόσου, περιορίζοντας τους ψευδείς συναγερμούς σε μόλις 2 περιπτώσεις.

  • Balanced Accuracy (97.14%): Ο μέσος όρος των δύο παραπάνω δεικτών επιβεβαιώνει ότι το μοντέλο διατηρεί μια ισορροπημένη και αξιόπιστη συμπεριφορά και για τις δύο κατηγορίες όγκων.

Ας δούμε τα 5 “λάθη” του μοντέλου:

  • 3 False Negatives: Ασθενείς με κακοήθεια που το μοντέλο ταξινόμησε λανθασμένα ως καλοήθεις. Στην ιατρική πράξη, αυτά είναι τα κρίσιμα περιστατικά που απαιτούν περαιτέρω διερεύνηση.

  • 2 False Positives: Ασθενείς με καλοήθεια που το μοντέλο χαρακτήρισε ως κακοήθεις, οδηγώντας σε ενδεχομένως περιττές βιοψίες ή άγχος για τον ασθενή.

xgb_auc <- roc(testData$Class, xgb_prob, levels = c("malignant", "benign"))$auc
cat("XGBoost AUC:", round(xgb_auc, 3), "\n")
## XGBoost AUC: 0.998
  • XGBoost AUC (0.998): Η τιμή αυτή είναι εξαιρετικά υψηλή και πρακτικά ταυτίζεται με αυτή του Random Forest. Ένα AUC της τάξης του 0.998 υποδηλώνει ότι το μοντέλο XGBoost διαθέτει σχεδόν τέλεια ικανότητα διάκρισης μεταξύ των δύο κατηγοριών. Σημαίνει ότι αν επιλέξουμε τυχαία έναν ασθενή με κακοήθεια και έναν με καλοήθεια, το μοντέλο θα δώσει υψηλότερη πιθανότητα κινδύνου στον κακοήθη ασθενή στο 99.8% των περιπτώσεων.

  • ROC Curve (Receiver Operating Characteristic): Η καμπύλη αυτή απεικονίζει τη σχέση μεταξύ Ευαισθησίας (True Positive Rate) και Ειδικότητας (False Positive Rate). Το γεγονός ότι το εμβαδόν κάτω από την καμπύλη (AUC) είναι τόσο κοντά στη μονάδα, δείχνει ότι ο XGBoost μπορεί να πετύχει πολύ υψηλή ευαισθησία (να μη χάνει κακοήθειες) διατηρώντας ταυτόχρονα πολύ χαμηλά επίπεδα ψευδών συναγερμών.

  • Αξιοπιστία: Η επίδοση αυτή επιβεβαιώνει ότι ο αλγόριθμος Gradient Boosting κατάφερε να εντοπίσει και τις πιο περίπλοκες σχέσεις μεταξύ των χαρακτηριστικών (όπως το Clump Thickness ή το Bland Chromatin).

  • Κλινική Σημασία: Σε ένα διαγνωστικό περιβάλλον, αυτό το αποτέλεσμα προσφέρει μεγάλη σιγουριά στον ιατρό. Το μοντέλο δεν κάνει απλώς “σωστές προβλέψεις”, αλλά έχει εκπαιδευτεί με τέτοιο τρόπο ώστε να διαχωρίζει με σαφήνεια τις παθολογικές από τις φυσιολογικές καταστάσεις, ελαχιστοποιώντας την περιοχή αβεβαιότητας

7b. Σύγκριση XGBoost με Random Forest

results <- data.frame(
  Model       = c("Random Forest", "XGBoost"),
  Accuracy    = c(as.numeric(rf_cm$overall["Accuracy"]), 
                  as.numeric(xgb_cm$overall["Accuracy"])),
  
  Sensitivity = c(as.numeric(rf_cm$byClass["Sensitivity"]), 
                  as.numeric(xgb_cm$byClass["Sensitivity"])),
  
  Specificity = c(as.numeric(rf_cm$byClass["Specificity"]), 
                  as.numeric(xgb_cm$byClass["Specificity"])),
  
  F1          = c(as.numeric(rf_cm$byClass["F1"]), 
                  as.numeric(xgb_cm$byClass["F1"])),
  
  AUC         = c(as.numeric(rf_auc), 
                  as.numeric(xgb_auc))
) %>% 
  mutate(across(where(is.numeric), ~ round(.x, 3)))

# Εμφάνιση του πίνακα
knitr::kable(results, caption = "Συγκριτική Ανάλυση Μοντέλων (RF vs XGBoost)")
Συγκριτική Ανάλυση Μοντέλων (RF vs XGBoost)
Model Accuracy Sensitivity Specificity F1 AUC
Random Forest 0.980 0.972 0.985 0.972 0.998
XGBoost 0.975 0.985 0.958 0.981 0.998

✅ Σύγκριση Μοντέλων XGBoost και Random Forest

Με βάση τις Μετρικές:
1. Συνολική Ακρίβεια (Accuracy): Νικητής είναι το Random Forest με 0.980, έναντι 0.975 του XGBoost (διαφορά 0.005 ή 0.5%).
2. Ευαισθησία (Sensitivity): Νικητής είναι το XGBoost με 0.985, έναντι 0.972 του Random Forest (διαφορά 0.013 ή 1.3%).
3. Ισορροπία (F1-Score): Νικητής είναι το XGBoost με 0.981, έναντι 0.972 του Random Forest (διαφορά 0.009 ή 0.9%).
4. Διαχωριστική Ικανότητα (AUC): Τα δύο μοντέλα ισοβαθμούν με το εντυπωσιακό 0.998.

Αν και το Random Forest είναι ελαφρώς πιο ακριβές συνολικά, το XGBoost θεωρείται ο ουσιαστικός νικητής για κλινική χρήση. Η διαφορά του κατά 1.3% στο Sensitivity είναι η πιο κρίσιμη, καθώς σημαίνει ότι εντοπίζει περισσότερα πραγματικά περιστατικά νόσου, μειώνοντας τις πιθανότητες λάθος διάγνωσης σε ασθενείς που έχουν ανάγκη θεραπείας.


Σας εξέπληξε κάτι στα αποτελέσματα;

1. Το Παράδοξο Accuracy vs F1 (Το βασικό): Το Random Forest κερδίζει στη συνολική ακρίβεια (0.980), αλλά το XGBoost κερδίζει στην ουσία (F1: 0.981). Αυτό συμβαίνει γιατί το Random Forest είναι “πρωταθλητής” στο να βρίσκει τους υγιείς, ενώ το XGBoost είναι “πρωταθλητής” στο να βρίσκει τους ασθενείς (Sensitivity: 0.985). Στην ιατρική, το δεύτερο είναι πολύ πιο σημαντικό.
2. Η “Τέλεια” Ισοπαλία στο AUC (0.998): Είναι πολύ σπάνιο δύο διαφορετικά μοντέλα να βγάζουν ακριβώς το ίδιο (και τόσο υψηλό) AUC. Αυτό μας λέει ότι τα δεδομένα σου είναι τόσο “καθαρά” που και τα δύο μοντέλα βρήκαν τον τέλειο τρόπο να ξεχωρίζουν το καλό από το κακό. Είναι σαν να δίνεις σε δύο διαφορετικούς οδηγούς ένα τέλειο αυτοκίνητο: και οι δύο θα κάνουν τον ίδιο κορυφαίο χρόνο.

Η έκπληξη είναι ότι ενώ το Random Forest μοιάζει “καλύτερο” στα χαρτιά λόγω Accuracy, το XGBoost είναι αυτό που θα εμπιστευόταν ένας γιατρός, γιατί «πιάνει» περισσότερους ασθενείς και έχει καλύτερη ισορροπία (F1-Score).

8. Δοκιμές με διαφορετικά eta

# Σενάριο Α: Υψηλό eta (0.3)
params_fast <- list(
  objective = "binary:logistic",
  eval_metric = "auc",
  eta = 0.3, # Υψηλός ρυθμός μάθησης
  max_depth = 4
)

xgb_fast <- xgb.train(
  params = params_fast,
  data = dtrain,
  nrounds = 500,
  evals = list(train = dtrain, test = dtest),
  early_stopping_rounds = 20,
  print_every_n = 10, # Θα εκτυπώνει ανά 10 γύρους για να βλέπεις τη διαφορά
  verbose = 1
)
## Multiple eval metrics are present. Will use test_auc for early stopping.
## Will train until test_auc hasn't improved in 20 rounds.
## 
## [1]  train-auc:0.989148  test-auc:0.987557 
## [11] train-auc:0.999330  test-auc:0.995870 
## [21] train-auc:0.999923  test-auc:0.996929 
## [31] train-auc:1.000000  test-auc:0.997141 
## [41] train-auc:1.000000  test-auc:0.997035 
## Stopping. Best iteration:
## [50] train-auc:1.000000  test-auc:0.996611
## 
## [50] train-auc:1.000000  test-auc:0.996611
# Σενάριο Β: Χαμηλό eta (0.01)
params_slow <- list(
  objective = "binary:logistic",
  eval_metric = "auc",
  eta = 0.01, # Χαμηλός ρυθμός μάθησης
  max_depth = 4
)

xgb_slow <- xgb.train(
  params = params_slow,
  data = dtrain,
  nrounds = 500,
  evals = list(train = dtrain, test = dtest),
  early_stopping_rounds = 20,
  print_every_n = 50, # Επειδή πάει αργά, εκτυπώνουμε ανά 50 γύρους
  verbose = 1
)
## Multiple eval metrics are present. Will use test_auc for early stopping.
## Will train until test_auc hasn't improved in 20 rounds.
## 
## [1]  train-auc:0.989148  test-auc:0.987557 
## [51] train-auc:0.994344  test-auc:0.994546 
## Stopping. Best iteration:
## [55] train-auc:0.994651  test-auc:0.994811
## 
## [55] train-auc:0.994651  test-auc:0.994811

Η χρήση του early_stopping_rounds = 20 μας αποκάλυψε πώς συμπεριφέρεται το μοντέλο σε κάθε περίπτωση:

  • Σενάριο Α (eta = 0.3): Το μοντέλο “τερμάτισε” την εκπαίδευση. Στον γύρο 31 είχε ήδη φτάσει σε train-auc: 1.000000 (τέλεια προσαρμογή στα δεδομένα εκπαίδευσης). Σταμάτησε στον γύρο 50, επειδή το AUC στο test set σταμάτησε να βελτιώνεται. Είναι ένα κλασικό παράδειγμα γρήγορης σύγκλισης που αγγίζει τα όρια του overfitting.

  • Σενάριο Β (eta = 0.01): Το μοντέλο σταμάτησε επίσης νωρίς (γύρος 55), αλλά για τον αντίθετο λόγο: δεν είχε προλάβει να μάθει αρκετά. Επειδή το βήμα μάθησης ήταν πολύ μικρό (0.01), η βελτίωση από γύρο σε γύρο ήταν τόσο ανεπαίσθητη που το early_stopping θεώρησε ότι το μοντέλο “κόλλησε” και σταμάτησε την εκπαίδευση πρόωρα.

✅ Συμπέρασμα Σύγκρισης eta

Ο αριθμός των γύρων που χρειάζεται ένα μοντέλο είναι άμεσα συνδεδεμένος με το eta. Σε σύγκριση με την αρχική μας επιλογή (eta = 0.1), η οποία αποτέλεσε τη “χρυσή τομή” επιτυγχάνοντας το μέγιστο AUC (0.998), παρατηρούμε τα εξής:

1. Με μεγάλο eta (0.3): Το μοντέλο συγκλίνει υπερβολικά επιθετικά. Φτάνουμε γρήγορα σε πολύ υψηλά σκορ (train-auc: 1.0), αλλά με αυξημένο κίνδυνο να “παπαγαλίσουμε” τα δεδομένα (overfitting), γεγονός που περιόρισε το test-auc σε ελαφρώς χαμηλότερα επίπεδα από το αρχικό μας μοντέλο.
2. Με μικρό eta (0.01): Χρειαζόμαστε πολύ περισσότερη “υπομονή” και χρόνο εκπαίδευσης. Στη συγκεκριμένη περίπτωση, το μοντέλο σταμάτησε πρόωρα (γύρος 55) όχι γιατί βρήκε τη βέλτιστη λύση, αλλά γιατί η πρόοδος ανά γύρο ήταν πολύ αργή για τα κριτήρια που του θέσαμε, αφήνοντας το μοντέλο “ανεκπαίδευτο” σε σχέση με την ισορροπημένη επιλογή του 0.1.
3. Με το αρχικό eta (0.1): Επιτεύχθηκε η “χρυσή τομή”. Το μοντέλο είχε τον απαραίτητο χρόνο να μάθει σε βάθος τα δεδομένα χωρίς να βιαστεί, οδηγώντας στο βέλτιστο αποτέλεσμα (AUC: 0.998) συγκριτικά με τις δύο ακραίες τιμές.

9. ROC Plots

roc_rf  <- roc(testData$Class, rf_probs, levels = c("malignant", "benign"))
## Setting direction: controls > cases
roc_xgb <- roc(testData$Class, xgb_prob, levels = c("malignant", "benign"))
## Setting direction: controls > cases
# Δημιουργία του γραφήματος
plot(roc_rf, col = "forestgreen", lwd = 2, main = "ROC Curve Comparison: RF vs XGBoost")
plot(roc_xgb, col = "steelblue", lwd = 2, add = TRUE) # add = TRUE για να μπει στο ίδιο γράφημα

# Προσθήκη λεζάντας
legend("bottomright", 
       legend = c(paste("Random Forest (AUC =", round(auc(roc_rf), 3), ")"), 
                  paste("XGBoost (AUC =", round(auc(roc_xgb), 3), ")")), 
       col = c("forestgreen", "steelblue"), lwd = 2)

Το παραπάνω γράφημα αποτελεί τον τελικό δείκτη αξιοπιστίας των μοντέλων ταξινόμησης. Η ανάλυση των καμπυλών οδηγεί στα εξής συμπεράσματα:

  • Διαχωριστική Ικανότητα (AUC 0.998): Η σχεδόν απόλυτη προσέγγιση της πάνω αριστερής γωνίας από τις καμπύλες και των δύο μοντέλων υποδηλώνει μια εξαιρετικά υψηλή ικανότητα διάκρισης μεταξύ καλοήθειας και κακοήθειας. Το εμβαδόν υπό την καμπύλη (AUC) επιβεβαιώνει στατιστικά ότι η πιθανότητα εσφαλμένης ταξινόμησης είναι ελάχιστη.

  • Συγκριτική Υπεροχή XGBoost: Η μπλε καμπύλη του XGBoost παρουσιάζει μια πιο οξεία προσέγγιση προς το σημείο (0,1) της απόλυτης ευαισθησίας. Ενώ το Random Forest (πράσινη γραμμή) εμφανίζει μια ελαφρώς πιο ομαλή καμπύλωση, το XGBoost καταφέρνει να “τετραγωνίσει” τη γωνία πιο αποτελεσματικά. Αυτή η γεωμετρική υπεροχή μεταφράζεται σε υψηλότερο True Positive Rate (Sensitivity) για το ίδιο επίπεδο ψευδώς θετικών αποτελεσμάτων.

  • Κλινική Αξιολόγηση: Η επικάλυψη των καμπυλών αποδεικνύει ότι και οι δύο αλγόριθμοι είναι εξαιρετικά ισχυροί. Ωστόσο, το XGBoost προκρίνεται ως το βέλτιστο σύστημα υποστήριξης κλινικών αποφάσεων, καθώς ελαχιστοποιεί το ρίσκο των ψευδώς αρνητικών αποτελεσμάτων, το οποίο είναι και το κρίσιμο ζητούμενο στην ογκολογία.