Come usare gli Alberi Decisionali per classificare i dati

Quando analizziamo un dataset con molte variabili e vogliamo prevedere una categoria — se un utente convertirà o no, se una pagina andrà in top 10, se una keyword è ad alta o bassa competizione — il primo problema è capire quali variabili contano davvero e come combinarle.
Gli alberi decisionali affrontano questo problema nel modo più naturale che ci sia: una sequenza di domande sì/no che, passo dopo passo, separano i dati in gruppi sempre più omogenei.

L’idea generale

Un albero decisionale è una struttura che prende decisioni in sequenza. Ogni nodo interno dell’albero pone una domanda (per esempio: “la lunghezza del petalo è maggiore di 2.45 cm?”), e in base alla risposta segue un ramo verso il nodo successivo. Si arriva così a una foglia, che assegna la classe di appartenenza.

La potenza dell’idea è che il risultato è intrinsecamente interpretabile: si può capire perché l’albero ha preso una certa decisione, semplicemente seguendo il percorso dalle radici alla foglia. Nessuna scatola nera.

Impurity e criteri di divisione

Come decide l’albero quale domanda fare per prima? L’obiettivo è trovare la divisione che separa i dati nel modo più “pulito” possibile. Il concetto centrale è l’impurità (impurity): una suddivisione perfetta è quella in cui tutti gli elementi di un gruppo appartengono alla stessa classe.

La misura più comune è l’indice di Gini. Per un nodo con \( K \) classi, dove \( p_k \) è la proporzione di elementi della classe \( k \), si definisce:

\( G = \sum_{k=1}^{K} p_k (1 – p_k) \\ \)

L’indice vale 0 quando il nodo è puro (tutti gli elementi della stessa classe), e raggiunge il massimo quando le classi sono uniformemente distribuite.
L’albero prova tutte le possibili divisioni su tutte le variabili e sceglie quella che riduce di più l’impurità media ponderata dei due nodi figli.

Esistono anche altre misure, come l’entropia (usata per costruire alberi C4.5), ma l’idea è la stessa: minimizzare l’incertezza.

Un albero decisionale in R sui dati iris

Costruiamo un albero decisionale con R usando il dataset iris, che contiene 150 fiori con le misure di sepali e petali di tre specie. Il nostro obiettivo è classificare la specie in base alle misure.

Prepariamo i dati:

data(iris)
library(rpart)

set.seed(123)
train_idx <- sample(1:nrow(iris), 0.8 * nrow(iris))
train <- iris[train_idx, ]
test  <- iris[-train_idx, ]

tree <- rpart(Species ~ ., data = train, method = "class")

Visualizziamo l’albero:

library(rpart.plot)
rpart.plot(tree, type = 2, extra = 104)
Albero decisionale: classificazione delle specie di iris
Albero decisionale: classificazione delle specie di iris

L’albero è semplicissimo. Parte dalla radice con una domanda sulla lunghezza del petalo. Se è minore di 2.45 cm, abbiamo la certezza che si tratta di setosa (tutti i 41 casi del training set finiscono lì). Se è maggiore, entriamo nel ramo successivo, che separa versicolor da virginica basandosi ancora sulla lunghezza del petalo, questa volta con soglia 4.75 cm.

La cosa notevole è che l’albero non ha usato affatto le misure dei sepali: le ha trovate irrilevanti per la classificazione, e le ha ignorate automaticamente. Questa è una forma implicita di selezione delle variabili: l’albero sceglie da solo quali metriche contano, e in che ordine.

Un esempio SEO: prevedere le pagine in top 10

Iris va bene per capire il meccanismo, ma proviamo qualcosa di più vicino al nostro lavoro quotidiano. Generiamo dati sintetici di 200 pagine web con metriche SEO reali — parole, leggibilità, velocità, backlink, immagini, keyword nel title, lunghezza della meta descrizione — e costruiamo un albero che preveda se una pagina arriverà in top 10.

set.seed(2026)

n <- 200
word_count      <- round(runif(n, 300, 3000))
readability     <- round(runif(n, 20, 80), 1)
page_speed_ms   <- round(runif(n, 500, 8000))
backlinks       <- round(runif(n, 0, 150))
images          <- round(runif(n, 0, 20))
keyword_in_title <- rbinom(n, 1, 0.35)
meta_desc_len   <- round(runif(n, 0, 165))

# target simulato: top_10 basato su combinazione di fattori
score <- (
  (backlinks > 30) * 0.30 +
  (keyword_in_title == 1) * 0.20 +
  (readability > 45 & readability < 70) * 0.15 +
  (word_count > 800 & word_count < 2200) * 0.15 +
  (page_speed_ms < 3000) * 0.10 +
  (meta_desc_len > 110 & meta_desc_len < 155) * 0.10
)
score <- score + rnorm(n, 0, 0.12)
top_10 <- factor(ifelse(score > 0.50, "si", "no"))

seo_data <- data.frame(word_count, readability, page_speed_ms,
                       backlinks, images, keyword_in_title,
                       meta_desc_len, top_10)

La variabile target top_10 è stata costruita in modo che dipenda da tutti questi fattori, ciascuno con un peso diverso — i backlink sono i più influenti, seguiti dalla presenza della keyword nel title, da una leggibilità nella fascia giusta, e così via. Aggiungiamo anche una componente casuale per simulare ciò che non possiamo misurare.

Alleniamo l’albero:

library(rpart)
train_idx <- sample(1:n, 0.7 * n)
tree_seo <- rpart(top_10 ~ ., data = seo_data[train_idx, ],
                  method = "class", control = rpart.control(cp = 0.01))

Visualizziamo l’albero risultante:

library(rpart.plot)
rpart.plot(tree_seo, type = 2, extra = 104)
Albero decisionale: previsione pagine in top 10
Albero decisionale: previsione pagine in top 10

L’albero ci dice qualcosa di molto interessante. La prima domanda — la variabile più discriminante — riguarda i backlink: se sono pochi, la pagina difficilmente entra in top 10, indipendentemente dagli altri fattori. Solo le pagine con un numero sufficiente di backlink passano al ramo successivo, dove l’albero valuta la leggibilità e la presenza della keyword nel title. È esattamente il genere di gerarchia che ci aspetteremmo da un’analisi SEO seria: prima l’autorità (backlink), poi la qualità on-page.

La feature importance conferma questa gerarchia:

tree_seo$variable.importance
Importanza delle variabili SEO
Importanza delle variabili SEO

I backlink dominano, come previsto. Poi vengono leggibilità e keyword nel title, mentre la velocità e la lunghezza della meta descrizione contribuiscono meno. L’albero non ha selezionato il numero di immagini come rilevante — nei nostri dati sintetici non lo era, e l’albero lo ha ignorato.

n.b. Questi dati sono sintetici: in un progetto reale con dati reali, l’albero rivelerebbe la gerarchia effettiva delle variabili per il vostro specifico contesto. L’esempio serve a mostrare il tipo di risposta che si ottiene, non a stabilire verità universali.

Un’avvertenza importante: l’albero individua schemi ricorrenti nei dati osservati, non relazioni di causa-effetto. Una variabile può risultare molto utile per prevedere il comportamento di una pagina senza esserne la causa diretta. Per esempio, se l’albero seleziona il CTR come variabile discriminante, non significa che aumentare il CTR farà salire la pagina in top 10 — potrebbe essere che le pagine in top 10 tendono ad avere un CTR più alto perché sono già in top 10. L’albero ci dice cosa è correlato, non cosa è causale.

Valutare l’accuratezza

Verifichiamo come si comporta sui dati di test:

pred <- predict(tree, newdata = test, type = "class")
table(pred, test$Species)

La tabella di contingenza (matrice di confusione) mostra quante predizioni sono corrette e quante no. L’accuratezza si calcola come:

\( \text{accuratezza} = \frac{\text{predizioni corrette}}{\text{predizioni totali}} \\ \)

Il nostro albero sbaglia pochissimo: è un modello semplice e i dati iris sono ben separabili. Nel mondo reale, però, le cose sono quasi sempre più complesse.

Overfitting e potatura

Qui arriviamo al punto delicato. Un albero decisionale può continuare a suddividersi finché ogni foglia contiene un solo elemento. In quel caso, l’accuratezza sul training set sarà del 100%. Ma l’albero avrà semplicemente memorizzato il dataset di addestramento invece di impararne le regolarità.

Questo fenomeno si chiama overfitting: il modello si adatta troppo ai dati di addestramento, catturando rumore e dettagli specifici che non si ripresenteranno sui dati nuovi.

L’overfitting è il problema principale degli alberi decisionali. Un albero troppo profondo memorizza il training set ma fallisce sui dati nuovi; uno troppo superficiale non coglie le strutture reali dei dati. Il punto giusto si trova con tecniche di validazione incrociata e potatura (pruning): si costruisce un albero volutamente grande e poi si tagliano i rami che non migliorano l’errore di previsione.

In R, si può potare l’albero con rpart usando il parametro cp (complexity parameter), che impedisce all’albero di fare divisioni che non riducono l’errore di almeno una certa soglia. La funzione printcp(tree) mostra l’errore di validazione incrociata per diverse dimensioni dell’albero, aiutando a scegliere il punto di taglio.

Importanza delle variabili

Uno dei sottoprodotti più utili di un albero decisionale è la feature importance: la misura di quanto ogni variabile contribuisce alla riduzione dell’impurità complessiva. In rpart si ottiene con:

tree$variable.importance

Questo ci dice, per esempio, che la lunghezza del petalo è di gran lunga la variabile più discriminante per l’iris — e le misure dei sepali contano poco o nulla.
Nel web marketing, un’analisi analoga si può fare per capire quali metriche separano davvero le pagine ad alte prestazioni da quelle a basse prestazioni.

Dai singoli alberi alle foreste: la Random Forest

Un singolo albero decisionale è instabile: un piccolo cambiamento nei dati di partenza può produrre un albero completamente diverso. Per ridurre questo problema, le Random Forest (foreste casuali) costruiscono centinaia di alberi su versioni leggermente diverse dei dati (campionamento con reinserimento) e ne mediano le previsioni. Il risultato è molto più stabile e accurato di un singolo albero, pur mantenendo gran parte dell’interpretabilità.

Se un singolo albero è come chiedere il parere di un esperto, una Random Forest è come consultare centinaia di esperti indipendenti e prendere la decisione per maggioranza.

Ne parleremo in un prossimo articolo.

FAQ

Quando usare un albero decisionale invece di una regressione logistica?
Quando i dati hanno interazioni complesse tra variabili (per esempio, l’effetto dell’età sulla conversione cambia a seconda del canale di acquisizione) e quando la priorità è l’interpretabilità.

L’albero può gestire variabili numeriche e categoriche insieme?
Sì, rpart gestisce naturalmente entrambi i tipi. Le variabili categoriche vengono convertite internamente in split binari.

Quanto deve essere profondo un albero?
Dipende dai dati. La regola pratica: usare la validazione incrociata (il plotcp() di rpart) per trovare la profondità che minimizza l’errore di previsione su dati non visti.

L’albero decisionale funziona anche per problemi di regressione?
Sì. Con method = "anova" invece di "class", l’albero prevede valori numerici (per esempio, il tempo sulla pagina atteso).

Perché l’albero ha usato solo la lunghezza del petalo?
Perché nei dati iris è la variabile più discriminante: da sola basta per separare una delle tre specie (setosa) e quasi separa le altre due. L’albero, essendo un algoritmo greedy, sceglie la variabile che dà la miglior divisione immediata.


Tra gli alberi decisionali, la discesa del gradiente e la riduzione delle dimensioni c’è un filo che li unisce: tutti risolvono il problema di dare struttura a dati complessi, ciascuno con il proprio approccio. La prossima tappa di questo percorso è la discesa del gradiente, il motore che fa funzionare buona parte del machine learning moderno.

Per approfondire

Se vuoi approfondire gli alberi decisionali, An Introduction to Statistical Learning di James, Witten, Hastie e Tibshirani è il punto di riferimento: spiega alberi, Random Forest e criteri di divisione con il giusto equilibrio tra intuizione e formalismo. I laboratori R sono liberamente disponibili online.