Un passo per ottenere risultati migliori con gli alberi decisionali

Un passo avanti per ottenere risultati ottimali con gli alberi decisionali

Sfondo, implementazione e miglioramento del modello

Tra gli alberi (foto dell'autore)

Gli alberi decisionali (DT) vengono abbandonati troppo presto.

Accade così:

Viene addestrato il DT. Insorge l’overfitting naturale. I parametri vengono sintonizzati (insoddisfacentemente). Alla fine, l’albero viene sostituito con Random Forest.

Sebbene ciò possa portare rapidi miglioramenti delle prestazioni, la sostituzione privilegia un algoritmo a “scatola nera”. Non è ideale. Solo un DT può produrre risultati intuitivi, offrire ai leader aziendali la capacità di confrontare gli scambi e dare loro un ruolo fondamentale nel miglioramento dei processi.

Ciò che non si può capire o spiegare, non viene messo in produzione. Questo è particolarmente vero in settori in cui anche piccoli fallimenti presentano rischi estremi, come il settore sanitario.

(Nota laterale: Le persone spesso chiedono “Le Random Forest producono importanze delle caratteristiche, non spiegano quali caratteristiche siano importanti?” Non proprio. Le importanze delle caratteristiche vengono quasi immediatamente interpretate come fattori causali (ad esempio, caratteristiche che hanno dipendenza dal target), ma non sono altro che fattori del modello. Sebbene utili solo per il tecnico da questo punto di vista, le importanze delle caratteristiche sono generalmente: (1) inutili nei modelli deboli (2) aumentano nelle caratteristiche con alta cardinalità e (3) sono parziali verso caratteristiche correlate. Questo è un altro filone di ricerca, ma in sostanza è questo il punto.)

Come prendono decisioni gli alberi decisionali

Se si continua ad utilizzare i DT, si preserverà la capacità di comunicare bene i risultati, ma come renderli performanti? La sintonizzazione dei parametri ti porta solo fino a un certo punto. E l’ingegneria delle caratteristiche ben ponderata dovrebbe comunque essere fatta.

Come si esprime, la struttura specifica dei dati delle caratteristiche potrebbe consentire loro di adattarsi meglio all’algoritmo sottostante degli alberi decisionali, il che a sua volta permette ai DT di prendere decisioni migliori.

Nel modo in cui viene implementato, il DT separa le classi creando confini decisionali ortogonali (divisioni perpendicolari) tra le classi in tutti i dati che gli vengono forniti. Lo fa in modo algoritmico e avido, prendendo le caratteristiche che forniscono la migliore divisione per prime, per poi passare a divisioni meno ottimali in altre caratteristiche.

Possiamo ispezionare visivamente le nostre caratteristiche per confini decisionali ortogonali. Di seguito, vediamo le caratteristiche del dataset sul cancro al seno disponibili pubblicamente. Nella parte superiore del grafico, tracciando “Worst Perimeter” e “Mean Perimeter” si ottiene un buon confine decisionale ortogonale che può separare bene le classi Maligne e Benigne. Pertanto, queste sarebbero ottime caratteristiche da includere nel modello DT.

Foto dell'autore

Il grafico inferiore sopra mostra “Mean Area” e “Mean Perimeter” per le quali il DT ha creato confini decisionali ortogonali (come fa di per sé), ma questi sono inutilmente convoluti. Probabilmente, qui sarebbe stata migliore una separazione diagonale, ma non è così che operano gli alberi decisionali. Inoltre, i DT sono molto sensibili anche a piccole variazioni nei dati di addestramento, come gli outlier, che si sa producono alberi significativamente diversi.

Per accogliere questo meccanismo unico e sottostante dei DT – e, in definitiva, migliorare le prestazioni e la generalità – può essere applicata l’Analisi delle Componenti Principali (PCA).

PCA migliora le prestazioni dei DT in due modi importanti:

(1) orienta insieme le caratteristiche chiave che spiegano la maggior varianza

(2) riduce lo spazio delle caratteristiche

In effetti, il processo PCA + DT ha evidenziato naturalmente le caratteristiche “Worst Perimeter” e “Mean Perimeter” che si vedono nel grafico superiore. Queste sono due delle variabili più predictive e, non sorprendentemente, hanno un ottimo confine decisionale ortogonale.

Implementazione del processo

Si ricorda che PCA è progettato per dati continui. Il dataset sul cancro al seno è interamente composto da variabili continue. (Un’altra nota laterale: vedo PCA utilizzato su variabili categoriche – non raccomandato. I livelli nominali non hanno distanze implicite, i livelli ordinali non sono sempre equidistanti e imporre rappresentazioni di distanza su caratteristiche discrete ri-costituisce generalmente la variabile in qualcosa di insignificante. Un altro argomento per un altro momento).

Iniziamo scaricando i pacchetti necessari e trasformiamo il nostro dataset sul cancro al seno in feature X e la variabile target y.

import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.decomposition import PCA
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix, precision_score, recall_score
import matplotlib.pyplot as plt
import seaborn as sns

# Carica il dataset sul cancro al seno
data = load_breast_cancer()
X = data.data
y = data.target

Per ispezionare, è possibile visualizzare l’intestazione del dataframe di questo dataset.

cancer = load_breast_cancer()
df = pd.DataFrame(np.c_[cancer['data'], cancer['target']], columns= np.append(cancer['feature_names'], ['target']))
df.head()
Foto dell'autore

Innanzitutto, addestra il DecisionTreeClassifier senza PCA e raccogli le predizioni (original_predictions).

# Suddivide i dati in training set e testing set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Addestra un Decision Tree Classifier sul dataset non trasformato con PCA
original_tree = DecisionTreeClassifier(random_state=42)
original_tree.fit(X_train, y_train)

# Predizioni sul dataset originale
original_predictions = original_tree.predict(X_test)

Ora, applica PCA per selezionare il numero minimo di dimensioni che possono spiegare la maggior parte della varianza nel set di addestramento. Invece di scegliere arbitrariamente quel numero di dimensioni, può essere utilizzato il “metodo del gomito” per identificare il numero di dimensioni che spiegherebbe il 99% della varianza (come codificato qui di seguito).

# Trova il numero ottimale di componenti PCA utilizzando il metodo del gomito
pca = PCA()
pca.fit(X_train)
explained_variance = pca.explained_variance_ratio_
cumulative_explained_variance = np.cumsum(explained_variance)

# Plot della varianza spiegata
plt.plot(range(1, len(cumulative_explained_variance) + 1), cumulative_explained_variance, marker='o')
plt.xlabel('Numero di componenti')
plt.ylabel('Varianza spiegata cumulativa')
plt.title('Varianza spiegata da PCA')
plt.grid()
plt.show()

# Determina il numero ottimale di componenti (punto di gomito)
optimal_num_components = np.where(cumulative_explained_variance >= 0.99999)[0][0] + 1
print(f"Numero ottimale di componenti PCA: {optimal_num_components}")

Visivamente, dal punto in cui il grafico forma un “gomito”, si trova che 6 componenti PCA spiegano il 99% della varianza del set di addestramento.

Foto dell'autore

Ora applica PCA per catturare 6 componenti principali sul set di addestramento. Puoi farlo utilizzando la decomposizione ai valori singolari (SVD) che è una tecnica standard di fattorizzazione di matrici (un processo al di fuori dello scopo di questo articolo). Come prima cosa, addestra il DecisionTreeClassifier sul set di addestramento trasformato con PCA e raccogli le predizioni (pca_predictions).

# Applica PCA con il numero ottimale di componenti
pca = PCA(n_components=optimal_num_components, svd_solver="full")
X_train_pca = pca.fit_transform(X_train)
X_test_pca = pca.transform(X_test)

# Addestra un Decision Tree Classifier sul dataset trasformato con PCA
pca_tree = DecisionTreeClassifier(random_state=42)
pca_tree.fit(X_train_pca, y_train)

# Predizioni sul dataset trasformato con PCA
pca_predictions = pca_tree.predict(X_test_pca)

# Matrice di confusione
pca_cm = confusion_matrix(y_test, pca_predictions)

# Precisione e Recupero per il dataset originale
original_precision = precision_score(y_test, original_predictions, average='weighted')
original_recall = recall_score(y_test, original_predictions, average='weighted')
original_accuracy = accuracy_score(y_test, original_predictions)

# Precisione e Recupero
pca_precision = precision_score(y_test, pca_predictions)
pca_recall = recall_score(y_test, pca_predictions)
pca_accuracy = accuracy_score(y_test, pca_predictions)

# Visualizza precisione e recupero
print(f"Dataset originale - Precisione: {original_precision:.4f}, Recupero: {original_recall:.4f}, Accuratezza: {original_accuracy:.4f}")
print(f"Dataset trasformato con PCA - Precisione: {pca_precision:.4f}, Recupero: {pca_recall:.4f}, Accuratezza: {pca_accuracy:.4f}")

Ora possiamo confrontare le nostre originali previsioni (non trasformate con PCA) con le previsioni con PCA per osservare eventuali miglioramenti relativi nelle nostre metriche di valutazione di precisione e richiamo.

Rispetto ai dati addestrati con l’albero decisionale originale, quando trasformiamo prima il dataset con PCA e poi addestriamo l’albero decisionale, otteniamo miglioramenti globali:

Possiamo tracciare le matrici di confusione per mostrare il miglioramento relativo della classificazione tra tumori maligni e benigni tra i due alberi decisionali.

# Traccia le matrici di confusioneplt.figure(figsize=(12, 5))plt.subplot(1, 2, 1)sns.heatmap(original_cm, annot=True, fmt="d", cmap="Blues", xticklabels=data.target_names, yticklabels=data.target_names)plt.title("Matrice di confusione dell'albero decisionale originale\nPrecisione: {:.2f}, Richiamo: {:.2f}".format(original_precision, original_recall))plt.xlabel("Predetto")plt.ylabel("Vero")plt.subplot(1, 2, 2)sns.heatmap(pca_cm, annot=True, fmt="d", cmap="Blues", xticklabels=data.target_names, yticklabels=data.target_names)plt.title("Matrice di confusione dell'albero decisionale con PCA\nPrecisione: {:.2f}, Richiamo: {:.2f}".format(pca_precision, pca_recall))plt.xlabel("Predetto")plt.ylabel("Vero")plt.tight_layout()plt.show()
Immagine dell'autore

Infine, è utile identificare quali delle nostre caratteristiche originali vengono utilizzate per generare le 6 principali componenti. Tecnicamente, PCA genera nuove caratteristiche che sono combinazioni lineari delle caratteristiche originali. Queste nuove caratteristiche sono ortogonali tra loro e sono classificate in base alla varianza che spiegano. Tuttavia, chiamando components_attribute è possibile identificare le caratteristiche utilizzate nella creazione di tali componenti.

# Ottieni il rapporto di varianza spiegata di ciascuna componente principaleexplained_variance_ratio = pca.explained_variance_ratio_# Ottieni le componenti PCApca_components = pca.components_# Crea un DataFrame per visualizzare i contributi delle caratteristiche originali per ogni componente principaledf_components = pd.DataFrame(data=pca_components, columns=data.feature_names)# Stampa le principali caratteristiche che contribuiscono a ciascuna componente principalefor i in range(optimal_num_components):    print(f"Principali caratteristiche per PC{i+1}:")    sorted_features = df_components.iloc[i].abs().sort_values(ascending=False)    print(sorted_features.head())    print("\nRapporto di Varianza Spiegata:", explained_variance_ratio[i])    print("=" * 50)

E così, per le 6 componenti principali che abbiamo selezionato, il modello ha creato queste utilizzando le seguenti 5 caratteristiche:

Immagine dell'autore

Conclusioni

Gli alberi decisionali vengono abbandonati troppo presto in favore di algoritmi più performanti. Sebbene le prestazioni più elevate siano importanti, potrebbero non essere le migliori – tale decisione dipende principalmente dalle esigenze degli stakeholder e dal chiarire perché un modello suggerisca un risultato specifico (vedere “intelligenza artificiale spiegabile“).

Invece di cercare l’algoritmo tecnologicamente più avanzato, lavorate per preparare al meglio i vostri dati attraverso un ingegneria delle caratteristiche oculate e l’Analisi delle Componenti Principali per dare agli alberi decisionali la loro migliore possibilità di rivelare le loro capacità intuitive di prendere decisioni.

Grazie per aver letto. Sono felice di connettermi con chiunque su LinkedIn! Se desiderate condividere sfide interessanti nell’ambito della scienza dei dati che state affrontando attualmente, lasciate un commento o un messaggio privato e sarò felice di cercare di esplorare/scrivere a riguardo.

I miei articoli più recenti:

Risoluzione degli errori di regressione logistica – Cosa significano, come farlo

Utilizzare le Reti Bayesiane per Prevedere il Volume dei Servizi Accessori negli Ospedali

Perché Bilanciare le Classi è Sopravvalutato