Albero decisionale in R: albero di classificazione con esempio
⚡ Riepilogo intelligente
Gli alberi decisionali in R dividono i dati in rami utilizzando semplici regole sì/no fino a quando ogni foglia non contiene una singola classe dominante. Questa guida illustra come costruire, visualizzare, valutare e ottimizzare un albero di classificazione rpart sul dataset dei sopravvissuti del Titanic.
Cosa sono gli alberi decisionali?
Alberi decisionali Gli alberi decisionali sono un algoritmo di apprendimento automatico versatile, in grado di eseguire sia attività di classificazione che di regressione. Si tratta di algoritmi molto potenti, capaci di adattarsi a set di dati complessi. Inoltre, gli alberi decisionali sono componenti fondamentali delle foreste casuali, che sono tra gli algoritmi di apprendimento automatico più potenti attualmente disponibili.
Prima di implementarlo tramite codice, è utile capire come un albero decide dove effettuare la divisione.
Come funziona un albero decisionale?
Un albero decisionale trasforma un set di dati in un diagramma di flusso di domande sì o no costruito da tre tipi di nodi: il radice contiene ogni osservazione di addestramento, un nodo interno pone una domanda su un predittore e divide i dati in due, e un foglia interrompe la suddivisione e restituisce la classe maggioritaria.
La crescita segue una procedura avida chiamata partizionamento binario ricorsivo:
- Valutare ogni suddivisione dei candidati. Per ogni predittore e punto di taglio, misurare il grado di impurità dei due gruppi risultanti.
- Tieni il migliore. La suddivisione che riduce maggiormente le impurità diventa la domanda che ci si pone in quel nodo.
- Ripeti per ogni bambino finché una regola di controllo non lo arresta: minsplit, minbucket, maxdepth o cp.
- Fesso. cp quindi pota i rami che non si autofinanziano, impedendo così all'albero di memorizzare il set di addestramento.
Poiché ogni domanda confronta una variabile con una soglia, l'algoritmo non necessita mai di scalatura o codifica fittizia.
Indice di Gini contro entropia negli alberi decisionali
Questa impurità può essere misurata in due modi e rpart ti permette di scegliere.
| Criteri | Indice di Gini | Entropia (guadagno di informazione) |
|---|---|---|
| Formula | 1 – somma dei quadrati delle proporzioni di classe | -somma di p volte log2(p) |
| Gamma (due classi) | 0 a 0.5 | 0 a 1 |
| Calcolo | Più veloce, senza logaritmo | Più lento, utilizza i logaritmi |
| impostazione rpart | Predefinito | parametri = elenco(split = “informazioni”) |
fit_entropy <- rpart(survived~., data = data_train, method = 'class', parms = list(split = "information"))
In pratica, entrambi i criteri scelgono la stessa suddivisione nella maggior parte dei casi, quindi l'indice di Gini predefinito è una scelta sicura.
Vantaggi e svantaggi degli alberi decisionali
I compromessi indicano quando un singolo albero è sufficiente e quando è opportuno passare a un insieme di alberi.
Vantaggi
- Completamente interpretabile: Il modello adattato è un diagramma che qualsiasi soggetto interessato può leggere.
- Pre-elaborazione minima: Non è necessario alcun ridimensionamento o normalizzazione e i fattori funzionano in modo nativo.
- Gestisce entrambi i compiti: Il metodo = 'class' si adatta a un classificatore e il metodo = 'anova' si adatta a un albero di regressione.
- Facile da addestrare: I grandi insiemi di dati possono essere elaborati in pochi secondi, quindi gli alberi rappresentano un utile punto di partenza.
Svantaggi
- Variabilità elevata: Una piccola modifica ai dati di addestramento può produrre un albero completamente diverso.
- Propenso all'overfitting: Un albero senza vincoli cresce finché ogni foglia non è pura, a meno che cp e maxdepth non lo limitino.
- Solo divisioni parallele agli assi: I confini diagonali richiedono numerosi tagli a forma di scala.
Il rimedio per le prime due debolezze è quello di fare una media di molti alberi, che è ciò che un foresta casuale fa.
Come addestrare e visualizzare un albero decisionale in R
Per costruire il tuo primo albero decisionale in R, dovrai seguire sette passaggi:
- Passaggio 1: importa i dati
- Passaggio 2: pulire il set di dati
- Passaggio 3: creare un set di training/test
- Passaggio 4: costruisci il modello
- Passaggio 5: fare una previsione
- Passaggio 6: misurare le prestazioni
- Passaggio 7: ottimizzare gli iperparametri
Passaggio 1) Importa i dati
Se sei curioso riguardo al destino del Titanic, puoi guardare questo video su Youtube. Lo scopo di questo set di dati è prevedere quali persone avranno maggiori probabilità di sopravvivere dopo la collisione con l’iceberg. Il set di dati contiene 13 variabili e 1309 osservazioni. Il set di dati è ordinato dalla variabile X.
set.seed(678) path <- 'https://raw.githubusercontent.com/guru99-edu/R-Programming/master/titanic_data.csv' titanic <-read.csv(path) head(titanic)
Produzione:
## X pclass survived name sex ## 1 1 1 1 Allen, Miss. Elisabeth Walton female ## 2 2 1 1 Allison, Master. Hudson Trevor male ## 3 3 1 0 Allison, Miss. Helen Loraine female ## 4 4 1 0 Allison, Mr. Hudson Joshua Creighton male ## 5 5 1 0 Allison, Mrs. Hudson J C (Bessie Waldo Daniels) female ## 6 6 1 1 Anderson, Mr. Harry male ## age sibsp parch ticket fare cabin embarked ## 1 29.0000 0 0 24160 211.3375 B5 S ## 2 0.9167 1 2 113781 151.5500 C22 C26 S ## 3 2.0000 1 2 113781 151.5500 C22 C26 S ## 4 30.0000 1 2 113781 151.5500 C22 C26 S ## 5 25.0000 1 2 113781 151.5500 C22 C26 S ## 6 48.0000 0 0 19952 26.5500 E12 S ## home.dest ## 1 St Louis, MO ## 2 Montreal, PQ / Chesterville, ON ## 3 Montreal, PQ / Chesterville, ON ## 4 Montreal, PQ / Chesterville, ON ## 5 Montreal, PQ / Chesterville, ON ## 6 New York, NY
tail(titanic)
Produzione:
## X pclass survived name sex age sibsp ## 1304 1304 3 0 Yousseff, Mr. Gerious male NA 0 ## 1305 1305 3 0 Zabour, Miss. Hileni female 14.5 1 ## 1306 1306 3 0 Zabour, Miss. Thamine female NA 1 ## 1307 1307 3 0 Zakarian, Mr. Mapriededer male 26.5 0 ## 1308 1308 3 0 Zakarian, Mr. Ortin male 27.0 0 ## 1309 1309 3 0 Zimmerman, Mr. Leo male 29.0 0 ## parch ticket fare cabin embarked home.dest ## 1304 0 2627 14.4583 C ## 1305 0 2665 14.4542 C ## 1306 0 2665 14.4542 C ## 1307 0 2656 7.2250 C ## 1308 0 2670 7.2250 C ## 1309 0 315082 7.8750 S
Dall'output head e tail, puoi notare che i dati non vengono mescolati. Questo è un grosso problema! Quando dividerai i tuoi dati tra un set di treni e un set di prova, selezionerai esclusivamente il passeggero della classe 1 e 2 (nessun passeggero della classe 3 rientra nell'80% superiore delle osservazioni), il che significa che l'algoritmo non vedrà mai le caratteristiche del passeggero della classe 3. Questo errore porterà a una previsione inadeguata.
Per superare questo problema, è possibile utilizzare la funzione sample().
shuffle_index <- sample(1:nrow(titanic)) head(shuffle_index)
Codice R dell'albero decisionale Spiegazione
- sample(1:nrow(titanic)): genera un elenco casuale di indici da 1 a 1309 (ovvero il numero massimo di righe).
Produzione:
## [1] 288 874 1078 633 887 992
Utilizzerai questo indice per mescolare il set di dati del Titanic.
titanic <- titanic[shuffle_index, ]
head(titanic)
Produzione:
## X pclass survived ## 288 288 1 0 ## 874 874 3 0 ## 1078 1078 3 1 ## 633 633 3 0 ## 887 887 3 1 ## 992 992 3 1 ## name sex age ## 288 Sutton, Mr. Frederick male 61 ## 874 Humblen, Mr. Adolf Mathias Nicolai Olsen male 42 ## 1078 O'Driscoll, Miss. Bridget female NA ## 633 Andersson, Mrs. Anders Johan (Alfrida Konstantia Brogren) female 39 ## 887 Jermyn, Miss. Annie female NA ## 992 Mamee, Mr. Hanna male NA ## sibsp parch ticket fare cabin embarked home.dest## 288 0 0 36963 32.3208 D50 S Haddenfield, NJ ## 874 0 0 348121 7.6500 F G63 S ## 1078 0 0 14311 7.7500 Q ## 633 1 5 347082 31.2750 S Sweden Winnipeg, MN ## 887 0 0 14313 7.7500 Q ## 992 0 0 2677 7.2292 C
Passaggio 2) Pulisci il set di dati
Diverse variabili contengono valori NA. La pulizia si articola in tre fasi:
- Elimina le variabili home.dest, cabin, name, X e ticket
- Creare variabili fattoriali per pclass e sopravvissute
- Lascia perdere il NA
library(dplyr) # Drop variables clean_titanic <- titanic %>% select(-c(home.dest, cabin, name, X, ticket)) %>% #Convert to factor level mutate(pclass = factor(pclass, levels = c(1, 2, 3), labels = c('Upper', 'Middle', 'Lower')), survived = factor(survived, levels = c(0, 1), labels = c('No', 'Yes'))) %>% na.omit() glimpse(clean_titanic)
Code Spiegazione
- select(-c(casa.dest, cabina, nome, X, biglietto)): elimina le variabili non necessarie
- pclass = factor(pclass, levels = c(1,2,3), labels= c('Superiore', 'Medio', 'Inferiore')): Aggiunge un'etichetta alla variabile pclass. 1 diventa Superiore, 2 diventa Medio e 3 diventa Inferiore
- factor(survived, levels = c(0,1), labels = c('No', 'Yes')): Aggiunge etichette alla variabile survived. 0 diventa No e 1 diventa Sì
- na.omit(): rimuove le osservazioni NA
Produzione:
## Observations: 1,045 ## Variables: 8 ## $ pclass <fctr> Upper, Lower, Lower, Upper, Middle, Upper, Middle, U... ## $ survived <fctr> No, No, No, Yes, No, Yes, Yes, No, No, No, No, No, Y... ## $ sex <fctr> male, male, female, female, male, male, female, male... ## $ age <dbl> 61.0, 42.0, 39.0, 49.0, 29.0, 37.0, 20.0, 54.0, 2.0, ... ## $ sibsp <int> 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, 1, 1, 0, 0, 0, 1, 1,... ## $ parch <int> 0, 0, 5, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 4, 0,... ## $ fare <dbl> 32.3208, 7.6500, 31.2750, 25.9292, 10.5000, 52.5542, ... ## $ embarked <fctr> S, S, S, S, S, S, S, S, S, C, S, S, S, Q, C, S, S, C...
Passaggio 3) Creare un set di training/test
Prima di addestrare il modello, devi eseguire due passaggi:
- Creare un treno e un set di test: addestrare il modello sul set di treni e testare la previsione sul set di test (ovvero dati invisibili)
- Installa rpart.plot dalla console
La pratica comune è quella di dividere i dati 80/20, l'80% dei dati serve per addestrare il modello e il 20% per fare previsioni. È necessario creare due frame di dati separati. Non vuoi toccare il set di prova finché non finisci di costruire il tuo modello. Puoi creare una funzione denominata create_train_test() che accetta tre argomenti.
create_train_test(df, size = 0.8, train = TRUE) arguments: -df: Dataset used to train the model. -size: Size of the split. By default, 0.8. Numerical value -train: If set to `TRUE`, the function creates the train set, otherwise the test set. Default value sets to `TRUE`. Boolean value.You need to add a Boolean parameter because R does not allow to return two data frames simultaneously.
create_train_test <- function(data, size = 0.8, train = TRUE) { n_row = nrow(data) total_row = size * n_row train_sample <- 1: total_row if (train == TRUE) { return (data[train_sample, ]) } else { return (data[-train_sample, ]) } }
Code Spiegazione
- function(data, size=0.8, train = TRUE): aggiunge gli argomenti nella funzione
- n_row = nrow(data): conta il numero di righe nel set di dati
- total_row = size*n_row: restituisce l'ennesima riga per costruire il treno
- train_sample <- 1:total_row: seleziona la prima riga fino all'ennesima riga
- if (train ==TRUE){ } else { }: se la condizione è vera, restituisce il train set, altrimenti il test set.
Puoi testare la tua funzione e controllare la dimensione.
data_train <- create_train_test(clean_titanic, 0.8, train = TRUE) data_test <- create_train_test(clean_titanic, 0.8, train = FALSE) dim(data_train)
Produzione:
## [1] 836 8
dim(data_test)
Produzione:
## [1] 209 8
Il set di dati di addestramento ha 836 righe e 8 colonne, mentre il set di dati di test ha 209 righe e le stesse 8 colonne.
Si utilizza la funzione prop.table() combinata con table() per verificare se il processo di randomizzazione è corretto.
prop.table(table(data_train$survived))
Produzione:
## ## No Yes ## 0.5944976 0.4055024
prop.table(table(data_test$survived))
Produzione:
## ## No Yes ## 0.5789474 0.4210526
In entrambi i dati, il numero di sopravvissuti è lo stesso, circa il 40%.
Installa rpart.plot
rpart.plot non è disponibile dalle librerie conda. Puoi installarlo dalla console:
install.packages("rpart.plot")
Passaggio 4) Costruisci il modello
Sei pronto per costruire il modello. La sintassi per la funzione ad albero decisionale rpart() è:
rpart(formula, data=, method='') arguments: - formula: The function to predict - data: Specifies the data frame - method: - "class" for a classification tree - "anova" for a regression tree
Usi il metodo della classe perché prevedi una classe.
library(rpart) library(rpart.plot) fit <- rpart(survived~., data = data_train, method = 'class') rpart.plot(fit, extra = 106)
Code Spiegazione
- rpart(): funzione per adattarsi al modello. Gli argomenti sono:
- sopravvissuto ~.: Formula degli alberi decisionali
- dati = treno_dati: set di dati
- metodo = 'class': adatta un modello binario
- rpart.plot(fit, extra= 106): Traccia l'albero. L'argomento extra è impostato su 106, che visualizza la probabilità della seconda classe più la percentuale di osservazioni in ciascun nodo. Puoi fare riferimento a vignette per ulteriori informazioni sulle altre scelte.
Produzione:
Si parte dal nodo radice, in cima al grafico e alla profondità 0 di 3:
- In alto c’è la probabilità complessiva di sopravvivenza. Mostra la percentuale di passeggeri sopravvissuti allo schianto. Il 41% dei passeggeri è sopravvissuto.
- Questo nodo chiede se il sesso del passeggero è maschile. In caso affermativo, si passa al figlio sinistro della radice (profondità 1). Il 63% sono maschi con una probabilità di sopravvivenza del 21%.
- Nel secondo nodo chiedi se il passeggero maschio ha più di 3.5 anni. Se sì, la possibilità di sopravvivenza è del 19%.
- Continui così per capire quali caratteristiche influiscono sulla probabilità di sopravvivenza.
Tieni presente che una delle tante qualità degli alberi decisionali è che richiedono pochissima preparazione dei dati. In particolare, non richiedono il ridimensionamento o la centratura delle funzionalità.
Per impostazione predefinita, la funzione rpart() utilizza Gini Misura dell'impurità per scegliere ogni suddivisione. Più alto è il valore di Gini, più le classi all'interno di quel nodo sono mescolate, quindi l'algoritmo sceglie sempre la suddivisione che lo riduce maggiormente.
Passaggio 5) Fai una previsione
Puoi prevedere il set di dati di test. Per fare una previsione, puoi utilizzare la funzione predit(). La sintassi di base di predit per l'albero decisionale R è:
predict(fitted_model, df, type = 'class') arguments: - fitted_model: This is the object stored after model estimation. - df: Data frame used to make the prediction - type: Type of prediction - 'class': for classification - 'prob': to compute the probability of each class - 'vector': Predict the mean response at the node level
Ora devi prevedere, per ciascuno dei 209 passeggeri del set di test, se il modello si aspetta che sopravvivano alla collisione.
predict_unseen <-predict(fit, data_test, type = 'class')
Code Spiegazione
- predire(fit, data_test, type = 'class'): prevedere la classe (0/1) del set di test
Ora confrontate le classi previste con i risultati reali.
table_mat <- table(data_test$survived, predict_unseen)
table_mat
Code Spiegazione
- tabella(data_test$survived, predict_unseen): Crea una tabella di contingenza delle classi previste rispetto al risultato reale
Produzione:
## predict_unseen ## No Yes ## No 106 15 ## Yes 30 58
Le righe rappresentano i valori effettivi, le colonne le previsioni. Il modello ha identificato correttamente 106 non sopravvissuti e 58 sopravvissuti, ma ha etichettato 15 non sopravvissuti come sopravvissuti e 30 sopravvissuti come deceduti.
Passaggio 6) Misurare le prestazioni
Puoi calcolare una misura di precisione per l'attività di classificazione con matrice di confusione:
Migliori matrice di confusione è una scelta migliore per valutare le prestazioni della classificazione. L'idea generale è contare il numero di volte in cui le istanze Vere vengono classificate come False.
Ogni riga in una matrice di confusione rappresenta un obiettivo effettivo, mentre ogni colonna rappresenta un obiettivo previsto. La prima riga di questa matrice considera i passeggeri deceduti (la classe negativa): 106 sono stati correttamente classificati come deceduti (Vero negativo), mentre 15 sono stati classificati erroneamente come sopravvissuti (Falso positivo). La seconda riga considera i sopravvissuti: 58 sono stati identificati correttamente (Vero positivo), mentre 30 sono stati mancati (Falso negativo).
Puoi calcolare il prova di precisione dalla matrice di confusione:
È la proporzione tra vero positivo e vero negativo sulla somma della matrice. Con R, puoi codificare come segue:
accuracy_Test <- sum(diag(table_mat)) / sum(table_mat)
Code Spiegazione
- sum(diag(table_mat)): somma della diagonale
- sum(table_mat): somma della matrice.
È possibile stampare la precisione del set di prova:
print(paste('Accuracy for test', accuracy_Test))
Produzione:
## [1] "Accuracy for test 0.784688995215311"
L'accuratezza sul set di test è 0.7847, ovvero il 78.47%. Ripeti l'esercizio sul set di training per vedere quanto il modello si adatta eccessivamente ai dati.
Passaggio 7) Ottimizza gli iperparametri
L'albero decisionale in R ha vari parametri che controllano gli aspetti dell'adattamento. Nella libreria dell'albero decisionale rpart, puoi controllare i parametri usando la funzione rpart.control(). Nel seguente codice, introduci i parametri che ottimizzerai. Puoi fare riferimento a vignette per altri parametri.
rpart.control(minsplit = 20, minbucket = round(minsplit/3), maxdepth = 30) Arguments: -minsplit: Set the minimum number of observations in the node before the algorithm perform a split -minbucket: Set the minimum number of observations in a terminal node, i.e. the leaf -maxdepth: Set the maximum depth of any node of the final tree. The root node is treated as depth 0
Procederemo come segue:
- Costruisci una funzione per restituire la precisione
- Regola la profondità massima
- Regola il numero minimo di campioni che un nodo deve avere prima di potersi dividere
- Regola il numero minimo di campioni che deve avere un nodo foglia
È possibile scrivere una funzione per visualizzare la precisione. Avvolgi semplicemente il codice che hai usato prima:
- predire: predire_unseen <- predire(fit, data_test, type = 'class')
- Produci tabella: table_mat <- table(data_test$survived, suggest_unseen)
- Precisione del calcolo: accuratezza_Test <- sum(diag(table_mat))/sum(table_mat)
accuracy_tune <- function(fit) { predict_unseen <- predict(fit, data_test, type = 'class') table_mat <- table(data_test$survived, predict_unseen) accuracy_Test <- sum(diag(table_mat)) / sum(table_mat) accuracy_Test }
Ora regola i parametri e verifica se riesci a migliorare il modello predefinito. Ricorda che devi superare un'accuratezza di 0.7847.
control <- rpart.control(minsplit = 4,
minbucket = round(5 / 3),
maxdepth = 3,
cp = 0)
tune_fit <- rpart(survived~., data = data_train, method = 'class', control = control)
accuracy_tune(tune_fit)
Produzione:
## [1] 0.7990431
Con il seguente parametro:
minsplit = 4
minbucket = round(5/3)
maxdepth = 3
cp = 0
L'accuratezza aumenta da 0.7847 a 0.7990, quindi l'albero ottimizzato supera la configurazione predefinita di circa 1.4 punti percentuali.
Alberi decisionali in R: Guida rapida alle funzioni
La tabella seguente elenca ogni funzione utilizzata nei sette passaggi precedenti, insieme al pacchetto che la fornisce e ai parametri che si aspetta in R.
| Biblioteca | Obiettivo | Funzione | Classe | Scheda Sintetica | Dettagli |
|---|---|---|---|---|---|
| parte | Albero di classificazione dei treni in R | parte() | classe | formula, df, metodo | |
| parte | Albero di regressione del treno | parte() | anova | formula, df, metodo | |
| parte | Traccia gli alberi | rpart.plot() | modello montato | ||
| base | predire | prevedere () | classe | modello montato, tipo | |
| base | predire | prevedere () | probabilmente | modello montato, tipo | |
| base | predire | prevedere () | vettore | modello montato, tipo | |
| parte | Parametri di controllo | rpart.control() | minsplit | Imposta il numero minimo di osservazioni nel nodo prima che l'algoritmo esegua una suddivisione | |
| minbucket | Imposta il numero minimo di osservazioni in un nodo terminale, ovvero la foglia | ||||
| profondità massima | Imposta la profondità massima di ogni nodo dell'albero finale. Il nodo radice viene considerato di profondità 0. | ||||
| parte | Modello di treno con parametri di controllo | parte() | formula, df, metodo, controllo |
Nota: addestrare il modello su dati di addestramento e testare le prestazioni su un set di dati invisibile, ovvero un set di test.




