Un passo per far sì che gli alberi decisionali producano risultati migliori |  di Gabe Verzino |  Novembre 2023

 | Intelligenza-Artificiale

Contesto, implementazione e miglioramento del modello

Tra gli alberi (foto dell’autore)

Gli alberi decisionali (DT) vengono abbandonati troppo presto.

Succede così:

Il DT è addestrato. Presenta un overfitting naturale. Gli iperparametri vengono ottimizzati (in modo insoddisfacente). Infine, l’albero viene sostituito con Random Forest.

Sebbene ciò possa rappresentare un rapido vantaggio in termini di prestazioni, la sostituzione dà priorità a un algoritmo “scatola nera”. Non è l’ideale. Solo un DT può produrre risultati intuitivi, offrire ai leader aziendali la capacità di confrontare i compromessi e conferire loro un ruolo fondamentale nel miglioramento dei processi.

Ciò che non puoi capire o addirittura spiegare, non arriva alla produzione. Ciò è particolarmente vero nei settori in cui anche i piccoli guasti presentano rischi estremi, come nel settore sanitario.

(Nota a margine: le persone spesso chiedono “Le foreste casuali producono l’importanza delle funzionalità, questo non spiega quali funzionalità sono importanti?” Non proprio. Le importanze delle funzionalità vengono quasi immediatamente interpretate come causale driver (ad esempio, funzionalità che hanno una dipendenza dal target), ma non sono altro che modello autisti. Sebbene siano utili al tecnico solo sotto questo aspetto, l’importanza delle caratteristiche è generalmente: (1) inutile nei modelli deboli (2) si gonfia in caratteristiche con elevata cardinalità e (3) tende a prediligere caratteristiche correlate. Questa è tutta un’altra linea di indagine, ma fondamentalmente è questo il problema.)

Come gli alberi decisionali prendono decisioni

Attenersi ai DT preserverà la tua capacità di comunicare bene i risultati, ma come renderli performanti? L’ottimizzazione degli iperparametri ti porta solo così lontano. E un’attenta progettazione delle funzionalità dovrebbe essere eseguita a prescindere.

A quanto pare, la struttura specifica dei dati delle caratteristiche potrebbe consentirgli di adattarsi meglio all’algoritmo DT sottostante, che a sua volta consente al DT di produrre decisioni migliori.

Sotto il cofano, i DT separano le classi creando confini decisionali ortogonali (divisioni perpendicolari) tra le classi tra tutti i dati forniti. Lo fa in modo avido e algoritmico: prendendo per prime le funzionalità che dividono meglio, per poi passare a suddivisioni meno ottimali in altre funzionalità.

Possiamo ispezionare visivamente le nostre caratteristiche per i confini decisionali ortogonali. Di seguito vengono visualizzate le funzionalità del set di dati sul cancro al seno disponibile al pubblico. Nel grafico in alto in basso, tracciando il “perimetro peggiore” e il “perimetro medio” si produce un buon confine decisionale ortogonale che può separare bene le classi maligne e benigne. Quindi, queste sarebbero ottime funzionalità per l’inclusione del modello DT.

Immagine dell’autore

Il grafico in basso sopra mostra “Area media” e “Perimetro medio” per i quali il DT ha stabilito confini decisionali ortogonali (come fa intrinsecamente), ma questi sono inutilmente contorti. Probabilmente qui sarebbe stata meglio una separazione diagonale, ma non è così che si dividono i classificatori DT. Inoltre, i DT sono molto sensibili anche alle piccole variazioni nei dati di training, come gli outlier, che sono noti per produrre alberi molto diversi.

Per accogliere questo meccanismo unico e sottostante dei DT e, in definitiva, migliorare le prestazioni e la generalizzabilità, è possibile applicare l’analisi delle componenti principali (PCA).

PCA migliora le prestazioni DT in due modi importanti:

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

(2) riduce lo spazio delle funzionalità

In effetti, il processo PCA + DT ha fatto emergere naturalmente le funzionalità “Perimetro peggiore” e “Perimetro medio” che vedi sopra nel grafico in alto. Questi sono due dei più predittivo variabili e non sorprende che abbiano un eccellente confine decisionale ortogonale.

Implementazione del processo

Ricordiamo che la PCA è progettata per dati continui. Il set di dati sul cancro al seno è interamente composto da variabili continue. (Un’altra nota a margine: vedo che PCA viene utilizzato su variabili categoriali – non raccomandato. I livelli nominali non hanno distanze implicite, i livelli ordinali non sono sempre equidistanti e l’applicazione di rappresentazioni di distanza su caratteristiche discrete generalmente ricostituisce la variabile in qualcosa di privo di significato. Un’altra tangente per un altro momento).

Iniziamo scaricando i pacchetti necessari e trasformando il nostro set di dati sul cancro al seno in funzionalità X e variabile di destinazione .

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

# Load the Breast Cancer dataset
data = load_breast_cancer()
X = data.data
y = data.target

Per l’ispezione è possibile chiamare l’intestazione del dataframe di questo set di dati.

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

Innanzitutto, addestra DecisionTreeClassifier senza PCA e raccogli tali previsioni (original_predictions).

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Fit a Decision Tree Classifier on the non-PCA-transformed dataset
original_tree = DecisionTreeClassifier(random_state=42)
original_tree.fit(X_train, y_train)

# Predictions on the original dataset
original_predictions = original_tree.predict(X_test)

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

# Finding the optimal number of PCA components using the elbow method
pca = PCA()
pca.fit(X_train)

explained_variance = pca.explained_variance_ratio_
cumulative_explained_variance = np.cumsum(explained_variance)

# Plot explained variance
plt.plot(range(1, len(cumulative_explained_variance) + 1), cumulative_explained_variance, marker='o')
plt.xlabel('Number of Components')
plt.ylabel('Cumulative Explained Variance')
plt.title('PCA Explained Variance')
plt.grid()
plt.show()

# Determine the optimal number of components (elbow point)
optimal_num_components = np.where(cumulative_explained_variance >= 0.99999)(0)(0) + 1

print(f"Optimal number of PCA components: {optimal_num_components}")

Basandosi visivamente sul punto in cui il grafico forma un “gomito”, rileva che 6 componenti PCA spiegano il 99% della varianza del set di allenamento.

Immagine dell’autore

Ora applica PCA per acquisire 6 componenti principali sul set di formazione. Puoi farlo utilizzando la decomposizione dei valori singolari (SVD), che è una tecnica di fattorizzazione di matrici standard (un processo che non rientra nell’ambito di questo caso). Come in precedenza, addestrare DecisionTreeClassifier sul set di training trasformato da PCA e raccogliere tali previsioni (pca_predictions).

# Apply PCA with the optimal number of components
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)

# Fit a Decision Tree Classifier on the PCA-transformed dataset
pca_tree = DecisionTreeClassifier(random_state=42)
pca_tree.fit(X_train_pca, y_train)

# Predictions on the PCA-transformed dataset
pca_predictions = pca_tree.predict(X_test_pca)

# Confusion matrix
pca_cm = confusion_matrix(y_test, pca_predictions)

# Precision and Recall scores for the original dataset
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)

# Precision and Recall scores
pca_precision = precision_score(y_test, pca_predictions)
pca_recall = recall_score(y_test, pca_predictions)
pca_accuracy = accuracy_score(y_test, pca_predictions)

# Output precision and recall scores
print(f"Original Dataset - Precision: {original_precision:.4f}, Recall: {original_recall:.4f}, Accuracy: {original_accuracy:.4f}")
print(f"PCA-Transformed Dataset - Precision: {pca_precision:.4f}, Recall: {pca_recall:.4f}, Accuracy: {pca_accuracy:.4f}")

Ora possiamo confrontare le nostre original_predictions (non trasformate in PCA) con le pca_predictions (trasformate in PCA) per osservare qualsiasi miglioramento relativo nelle nostre metriche di valutazione di accuratezza, precisione e richiamo.

Rispetto ai dati addestrati DT originali, quando trasformiamo prima il set di dati tramite PCA e poi eseguiamo l’addestramento DT, otteniamo miglioramenti su tutta la linea:

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

# Plot the confusion matrices
plt.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("Original Decision Tree Confusion Matrix\nPrecision: {:.2f}, Recall: {:.2f}".format(original_precision, original_recall))
plt.xlabel("Predicted")
plt.ylabel("True")

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("Decision Tree with PCA Confusion Matrix\nPrecision: {:.2f}, Recall: {:.2f}".format(pca_precision, pca_recall))
plt.xlabel("Predicted")
plt.ylabel("True")

plt.tight_layout()
plt.show()

Immagine dell’autore

Infine, è utile identificare quali delle nostre funzionalità originali vengono utilizzate per generare i 6 componenti principali. Tecnicamente, PCA genera nuove funzionalità che sono combinazioni lineari delle funzionalità originali. Queste nuove funzionalità sono ortogonali tra loro e sono classificate in ordine di varianza che spiegano. Tuttavia, chiamando attributo_componenti può identificare le caratteristiche usato nella creazione di tali componenti.

# Get the explained variance ratio of each principal component
explained_variance_ratio = pca.explained_variance_ratio_

# Get the PCA components
pca_components = pca.components_

# Create a DataFrame to display the contributions of original features to each principal component
df_components = pd.DataFrame(data=pca_components, columns=data.feature_names)

# Print the top features contributing to each principal component
for i in range(optimal_num_components):
print(f"Top features for PC{i+1}:")
sorted_features = df_components.iloc(i).abs().sort_values(ascending=False)
print(sorted_features.head())
print("\nExplained Variance Ratio:", explained_variance_ratio(i))
print("=" * 50)

E così, per i 6 componenti principali che abbiamo selezionato, il modello ha creato quelli che utilizzano le seguenti 5 funzionalità:

Immagine dell’autore

Conclusione

Gli alberi decisionali vengono abbandonati troppo presto al posto di algoritmi più performanti. Sebbene la prestazione più elevata sia importante, potrebbe non essere la migliore: tale decisione dipende in ultima analisi dalle esigenze delle parti interessate e dalla spiegazione del motivo per cui un modello suggerisce un risultato particolare (vedere “IA spiegabile“).

Invece di ricorrere all’algoritmo tecnicamente più avanzato, lavora per preparare in modo ottimale i tuoi dati attraverso un’attenta progettazione delle funzionalità e l’analisi dei componenti principali per dare agli alberi decisionali le migliori possibilità di rivelare le loro capacità decisionali intuitive.

Fonte: towardsdatascience.com

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *