Δένδρα Αποφάσεων και Random Forests

Δένδρα Αποφάσεων και Random Forests

Εισαγωγή

Στο post αυτό θα παρουσιάσουμε κάποια παραδείγματα για σχετικά με τις μέθοδους κατηγοριοποίησης με την ονομασία Δένδρα Αποφάσεων και Random Forests. Θα παρουσιάσουμε επίσης και το πακέτο randomForestExplainer που χρησιμοποιείται για την επεξήγηση των μονέλων random forest. Όλα αυτά, μέσα από παραδείγματα σε R.

Ειδικότερα, θα χρεισιμοποιήσουμε το iris dataset και τις βιβλιοθήκες/πακέτα rpart, rattle, rpart.plot, RColorBrewer και randomForestExplainer. Ξεκινάμε φορτώνοντας τς εν λόγω βιβλιοθήκες (σε περίπτωση που δεν είναι εγκατεστημένες, θα πρέπει πρώτα νατις εγκαταστήσετε).

library(rpart)
library(rattle)
## Rattle: A free graphical interface for data science with R.
## Version 5.2.0 Copyright (c) 2006-2018 Togaware Pty Ltd.
## Type 'rattle()' to shake, rattle, and roll your data.
library(rpart.plot)
library(RColorBrewer)
library(randomForest)
## randomForest 4.6-14
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## The following object is masked from 'package:rattle':
## 
##     importance
library(randomForestExplainer)

Στη συνέχεια, χωρίζουμε το iris dataset στε δύο κομμάτια. Το ένα θα το χρησιμοποιήσουμε για τη δημιουργία/εκπαίδευση των μοντέλων μας και αποτελείται από το 80% του συνόλου των δεδομένων. Το άλλο θα το χρησιμοποιήσουμε για την αξιολόγηση των μοντέλων και αποτελείται από το υπόλοιπο 20%. Το πρώτο κομμάτι το αποθηκεύουμε στη μεταβλητή train ενώ το δεύτερο στη μεταβλητή test. Παρατηρήστε, ότι για τη δημιουργία τους έχουμε πάρει το 80% των γραμμών που αποτελούν το κάθε είδος ώστε και στο train dataset να έχουμε ίσο αριθμό γραμμών για κάθε είδος.

set.seed(100)
idx=sample(50,0.8*50)
idx=c(idx,idx+50,idx+100)
train=iris[idx,]
test=iris[-idx,]
table(train$Species)
## 
##     setosa versicolor  virginica 
##         40         40         40
table(test$Species)
## 
##     setosa versicolor  virginica 
##         10         10         10

Δένδρα Αποφάσεων (Decission Trees)

Για να δημιουργήσουμε ένα δένδρο αποφάσεων μπορούμε να χρησιμοποιήσουμε την εντολή rpart από την ομώνυμη βιβλιοθήκη.

tree_model=rpart(Species~.,data=train,method ="class")

Μπορούμε να δούμε το δένδρο

fancyRpartPlot(tree_model)

Το γράφημμα αποκαλύπτει ότι το δένδρο στηρίζεται αποκλειστικά στις μεταβλητές Petal.Length και Petal.Width για την ταξινόμηση. Για την αξιολόγησή του, χρησιμοποιούμε το δένδρο για να ταξινομήοσυμε τα δείγματα του test dataset.

tree_test=predict(tree_model,test[,-5],type="class")

Τέλος, συγκρίνουμε τα αποτελέσματα του μοντέλου μας με τα πραγματικά.

table(test$Species,tree_test)
##             tree_test
##              setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0         10         0
##   virginica       0          1         9
prop.table(table(test$Species,tree_test))[1,1]+prop.table(table(test$Species,tree_test))[2,2]+
  prop.table(table(test$Species,tree_test))[3,3]
## [1] 0.9666667

Βλέπουμε, ότι όλα τα δείγματα του test ταξινομούνται σωστά με εξαίρεση ένα του είδους virginica που χαρακτηρίζεται ως versicolor. Η δε ακρίβεια του δένδρου-μοντέλου είναι 96.7%.

Random Forests

Ένας τρόπος για να βελτιώσουμε την απόδοση του προηγούμενου μοντέλου, είναι - να πάρουμε τυχαία δείγματα από το train dataset, - με καθένα από αυτά να δημιουργήσουμε ένα δένδρο αποφάσεων, - τέλος, να συνδυάσουμε όλα τα παραπάνω δένδρα σε ένα μοντέλο (επιστρέφοντας ως αποτέλεσμα το είδος που επιλέγουν τα περισσότερα δένδρα)

forest_model <- randomForest(Species~.,
                             data=train, 
                             importance=TRUE, 
                             ntree=600)

Η παράμετρος ntree=600 δίνει εντολή να κατασκευαστουν 600 δένδρα αποφάσεων ενώ η importance=TRUE δίνει εντολή να υπολογιστεί η σημαντκότητα κάθε μεταβλητής. Την τελευταία μπορούμε να τη δούμε με την εντολή

varImpPlot(forest_model)

Οι σημαντικότερες μεταβλτές η, σύμφωνα με το Random Forest, είναι οι Petal.width και Petal.Length.

Για την αξιολόγηση του μοντέλου έχουμε

res <- predict(forest_model,test[,-5],type="class")
table(test$Species,tree_test)
##             tree_test
##              setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0         10         0
##   virginica       0          1         9
prop.table(table(test$Species,tree_test))[1,1]+prop.table(table(test$Species,tree_test))[2,2]+
  prop.table(table(test$Species,tree_test))[3,3]
## [1] 0.9666667

Στην περίπτωσή μας, τα αποτελέσματα της αξιολόγησης του Random Forest είναι τα ίδια με αυτά του δένδρου αποφάσεων. Αυτό οφείλεται στο σύνολο δεδομένων. Γενικά η απόδοση των Random Forests είναι καλύτερη. Το μειονέκτημά τους είναι ότι πλέον δεν είναι δυνατό να δημιουργήσει κανείς ένα απλό διάγραμμα που να εξηγεί το πως δουλεύουν όπως κάναμε πριν με την fancyRpartPlot.

Πακέτο randomForestExplainer

Η βιλιοθήκη randomForestExplainer βοηθά στην κατανόηση των μοντέλων που κατασκευάζει η randomForest. Ένα βασικό κριτήριο για την αξιολόγηση της σημαντικότητας κάθε μεταβλητής είναι το πόσο ψηλά/νωρίς εμφανίζεται διακλάδωση με βάση αυτήν τη μεταβλητή (minimal depth). Για παράδειγμα, στο δένδρο που κατασκευάσαμε στην ενότητα Δένδρα Αποφάσεων (Decission Trees) η μεταβλητή Petal.Length έχει minimal depth αφού είναι ρίζα (root) ενώ η Petal.Width έχει minimal depth 1. Η εντολή min_depth_distribution υπολογίζει το ελάχιστο βάθος για κάθε μεταβλητή και για κάθε δένδρο του δάσους.

min_depth_frame=min_depth_distribution(forest_model)
head(min_depth_frame)
##   tree     variable minimal_depth
## 1    1 Petal.Length             2
## 2    1  Petal.Width             1
## 3    1 Sepal.Length             0
## 4    1  Sepal.Width             1
## 5    2 Petal.Length             2
## 6    2  Petal.Width             0

Μπορούμε δε να απεικονίσουμε γραφικά το αποτέλεσμα

plot_min_depth_distribution(min_depth_frame)

Περισσότερες λεπτομέριες για τις δυνατότητες του πακέτου μπορείτε να διαβάσετε και στη σελίδα του CRAN για το randomForestExplainer