🌺 Classificazione con Iris Dataset e Scikit-Learn

Impara algoritmi di classificazione ML con il dataset più famoso

Introduzione

Benvenuto nel mondo della classificazione con Machine Learning! Useremo il famoso dataset Iris per imparare a classificare specie di fiori basandoci sulle dimensioni di petali e sepali. Questo è il dataset “Hello World” del ML ed è perfetto per imparare gli algoritmi di classificazione.

Scenario Reale:
Lavorerai come botanico digitale che deve creare un sistema per identificare automaticamente specie di fiori Iris. Useremo SVM, KNN e altri algoritmi per costruire classificatori accurati.

⚠️ ATTENZIONE: COPIA BLOCCATA

Il codice è protetto da sistema anti-copia. Dovrai SCRIVERE manualmente tutto il codice per imparare veramente! 🚫📋

Parte 1: Caricamento e Esplorazione Dataset

▶ Importazione e Caricamento Iris Dataset

1
Crea una nuova cella su Google Colab e carica il dataset:
PYTHON
# IMPORT LIBRERIE PER CLASSIFICAZIONE ML
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# Algoritmi di classificazione che useremo
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.naive_bayes import GaussianNB

# Configurazione visualizzazione
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = (12, 8)
plt.rcParams['font.size'] = 12

print("✅ Librerie ML importate correttamente!")
print("📊 Algoritmi disponibili: KNN, SVM, Decision Tree, Random Forest, Naive Bayes")

▶ Caricamento e Analisi Dataset Iris

2
Carica e esplora il dataset Iris:
PYTHON
# 2. CARICAMENTO DATASET IRIS
print("🌺 CARICAMENTO DATASET IRIS")
print("="*50)

# Carica dataset Iris da Scikit-Learn
iris = datasets.load_iris()
X = iris.data  # Features: [sepal_length, sepal_width, petal_length, petal_width]
y = iris.target  # Target: 0=setosa, 1=versicolor, 2=virginica
feature_names = iris.feature_names
target_names = iris.target_names

# Converti in DataFrame per analisi più facile
df_iris = pd.DataFrame(X, columns=feature_names)
df_iris['species'] = y
df_iris['species_name'] = df_iris['species'].map({i: name for i, name in enumerate(target_names)})

print(f"📊 INFORMAZIONI DATASET:")
print(f"  • Numero campioni: {X.shape[0]}")
print(f"  • Numero features: {X.shape[1]}")
print(f"  • Features: {', '.join(feature_names)}")
print(f"  • Classi target: {', '.join(target_names)}")
print(f"  • Valori target: 0={target_names[0]}, 1={target_names[1]}, 2={target_names[2]}")

print(f"\n📋 PRIME 10 RIGHE DEL DATASET:")
print(df_iris.head(10))

print(f"\n📈 STATISTICHE DESCRITTIVE:")
print(df_iris.describe())

print(f"\n🎯 DISTRIBUZIONE CLASSI:")
distribuzione = df_iris['species_name'].value_counts()
for specie, count in distribuzione.items():
    percentuale = (count / len(df_iris)) * 100
    print(f"  • {specie}: {count} campioni ({percentuale:.1f}%)")

print(f"\n🔍 VALORI MANCANTI:")
print(df_iris.isnull().sum())

Parte 2: Visualizzazione e Analisi Dati

▶ Visualizzazioni per Capire i Dati

3
Visualizza le relazioni tra features e classi:
PYTHON
# 3. VISUALIZZAZIONE DATASET IRIS
print("🎨 VISUALIZZAZIONE COMPLETA DATASET IRIS")
print("="*50)

# Configura colori per le specie
colors = {'setosa': '#FF6B6B', 'versicolor': '#4ECDC4', 'virginica': '#45B7D1'}
markers = {'setosa': 'o', 'versicolor': 's', 'virginica': '^'}

print("Creazione visualizzazioni...")

# Creazione figura con multiple visualizzazioni
fig = plt.figure(figsize=(18, 12))
fig.suptitle('Analisi Visuale Dataset Iris', fontsize=20, fontweight='bold')

# 3.1 Pairplot (Scatter Matrix)
print("\n1. Pairplot - Relazioni tra tutte le features...")
import warnings
warnings.filterwarnings('ignore')

# Pairplot semplificato
axes = []
for i in range(4):
    for j in range(4):
        ax = plt.subplot(4, 4, i*4 + j + 1)
        axes.append(ax)
        
        if i == j:
            # Diagonali: istogrammi
            for idx, specie in enumerate(target_names):
                data = df_iris[df_iris['species_name'] == specie][feature_names[i]]
                ax.hist(data, alpha=0.5, label=specie, color=colors[specie])
            ax.set_xlabel(feature_names[i])
            if i == 0:
                ax.legend(loc='upper right', fontsize=8)
        else:
            # Off-diagonal: scatter plots
            for idx, specie in enumerate(target_names):
                x_data = df_iris[df_iris['species_name'] == specie][feature_names[j]]
                y_data = df_iris[df_iris['species_name'] == specie][feature_names[i]]
                ax.scatter(x_data, y_data, alpha=0.6, label=specie, 
                          color=colors[specie], marker=markers[specie], s=30)
            ax.set_xlabel(feature_names[j])
            ax.set_ylabel(feature_names[i])
            if i == 0 and j == 3:
                ax.legend(loc='upper right', fontsize=8)

plt.tight_layout()
plt.show()

# 3.2 Boxplot per feature
print("\n2. Boxplot - Distribuzione per specie...")
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Distribuzione Features per Specie di Iris', fontsize=16)

for idx, feature in enumerate(feature_names):
    ax = axes[idx // 2, idx % 2]
    box_data = [df_iris[df_iris['species_name'] == specie][feature] for specie in target_names]
    bp = ax.boxplot(box_data, labels=target_names, patch_artist=True)
    
    # Colori per i box
    for patch, color in zip(bp['boxes'], [colors[s] for s in target_names]):
        patch.set_facecolor(color)
        patch.set_alpha(0.6)
    
    ax.set_title(f'Distribuzione {feature}')
    ax.set_ylabel('cm')
    ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 3.3 Heatmap correlazioni
print("\n3. Heatmap - Correlazioni tra features...")
plt.figure(figsize=(10, 8))
correlation_matrix = df_iris[feature_names].corr()
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0, 
            square=True, linewidths=1, cbar_kws={"shrink": 0.8})
plt.title('Matrice di Correlazione tra Features', fontsize=14, pad=20)
plt.tight_layout()
plt.show()

print("✅ Visualizzazioni completate!")

Parte 3: Preparazione Dati per Classificazione

▶ Split Train/Test e Preprocessing

4
Prepara i dati per gli algoritmi di classificazione:
PYTHON
# 4. PREPARAZIONE DATI PER CLASSIFICAZIONE
print("⚙️  PREPARAZIONE DATI PER GLI ALGORITMI DI CLASSIFICAZIONE")
print("="*60)

# 4.1 Split in training e test set
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

print(f"📊 SPLIT DATI:")
print(f"  • Dimensione dataset completo: {X.shape}")
print(f"  • Training set: {X_train.shape[0]} campioni (70%)")
print(f"  • Test set: {X_test.shape[0]} campioni (30%)")

# Verifica distribuzione classi nei due set
print(f"\n🎯 DISTRIBUZIONE CLASSI NEI SET:")
train_dist = np.bincount(y_train)
test_dist = np.bincount(y_test)

for i, specie in enumerate(target_names):
    train_pct = (train_dist[i] / len(y_train)) * 100
    test_pct = (test_dist[i] / len(y_test)) * 100
    print(f"  • {specie}:")
    print(f"    Training: {train_dist[i]} campioni ({train_pct:.1f}%)")
    print(f"    Test: {test_dist[i]} campioni ({test_pct:.1f}%)")

# 4.2 Normalizzazione delle features
print(f"\n🔢 NORMALIZZAZIONE FEATURES:")
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print("  Features scalate con StandardScaler (media=0, deviazione=1)")
print(f"  Esempio prima riga training (originale): {X_train[0]}")
print(f"  Esempio prima riga training (scalata): {X_train_scaled[0]}")

# 4.3 Visualizzazione dati dopo scaling
print(f"\n🎨 CONFRONTO DATI PRIMA E DOPO SCALING...")

fig, axes = plt.subplots(1, 2, figsize=(15, 6))

# Dati originali
for i, specie in enumerate(target_names):
    mask = y_train == i
    axes[0].scatter(X_train[mask, 2], X_train[mask, 3], 
                   alpha=0.6, label=specie, color=colors[specie], 
                   marker=markers[specie], s=50)
axes[0].set_title('Dati Originali (Training Set)')
axes[0].set_xlabel('Petal Length (cm)')
axes[0].set_ylabel('Petal Width (cm)')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# Dati scalati
for i, specie in enumerate(target_names):
    mask = y_train == i
    axes[1].scatter(X_train_scaled[mask, 2], X_train_scaled[mask, 3], 
                   alpha=0.6, label=specie, color=colors[specie], 
                   marker=markers[specie], s=50)
axes[1].set_title('Dati Scalati (Training Set)')
axes[1].set_xlabel('Petal Length (scalata)')
axes[1].set_ylabel('Petal Width (scalata)')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print("✅ Preparazione dati completata!")

Parte 4: Implementazione Algoritmi di Classificazione

▶ Addestramento Multipli Algoritmi

5
Addestra e confronta diversi algoritmi di classificazione:
PYTHON
# 5. IMPLEMENTAZIONE ALGORITMI DI CLASSIFICAZIONE
print("🤖 ADDESTRAMENTO ALGORITMI DI CLASSIFICAZIONE")
print("="*60)

# Definizione dei modelli da testare
models = {
    'K-Nearest Neighbors': KNeighborsClassifier(n_neighbors=5),
    'Support Vector Machine': SVC(kernel='rbf', C=1.0, gamma='scale', probability=True),
    'Decision Tree': DecisionTreeClassifier(max_depth=4, random_state=42),
    'Random Forest': RandomForestClassifier(n_estimators=100, max_depth=4, random_state=42),
    'Naive Bayes': GaussianNB()
}

# Dizionario per salvare risultati
results = {
    'Model': [],
    'Train Accuracy': [],
    'Test Accuracy': [],
    'Cross-Val Score': []
}

print("⚡ Addestramento modelli in corso...\n")

# Addestra e valuta ogni modello
for name, model in models.items():
    # Addestramento
    model.fit(X_train_scaled, y_train)
    
    # Predizioni
    y_train_pred = model.predict(X_train_scaled)
    y_test_pred = model.predict(X_test_scaled)
    
    # Calcolo accuracy
    train_acc = accuracy_score(y_train, y_train_pred)
    test_acc = accuracy_score(y_test, y_test_pred)
    
    # Cross-validation score (5-fold)
    cv_scores = cross_val_score(model, X_train_scaled, y_train, cv=5)
    cv_mean = cv_scores.mean()
    
    # Salva risultati
    results['Model'].append(name)
    results['Train Accuracy'].append(train_acc)
    results['Test Accuracy'].append(test_acc)
    results['Cross-Val Score'].append(cv_mean)
    
    # Stampa risultati parziali
    print(f"📊 {name}:")
    print(f"  • Training Accuracy: {train_acc:.3f}")
    print(f"  • Test Accuracy: {test_acc:.3f}")
    print(f"  • Cross-Val Mean: {cv_mean:.3f}")
    print()

# Converti risultati in DataFrame
results_df = pd.DataFrame(results)
results_df = results_df.sort_values('Test Accuracy', ascending=False)

print("🏆 CLASSIFICA MODELLI PER TEST ACCURACY:")
print(results_df.to_string(index=False))

# Visualizzazione confronto modelli
print("\n🎨 VISUALIZZAZIONE CONFRONTO MODELLI...")

fig, ax = plt.subplots(figsize=(12, 8))
x = np.arange(len(results_df))
width = 0.25

bars1 = ax.bar(x - width, results_df['Train Accuracy'], width, label='Train Accuracy', 
              color='skyblue', alpha=0.8)
bars2 = ax.bar(x, results_df['Test Accuracy'], width, label='Test Accuracy', 
              color='lightgreen', alpha=0.8)
bars3 = ax.bar(x + width, results_df['Cross-Val Score'], width, label='Cross-Val Score', 
              color='salmon', alpha=0.8)

ax.set_xlabel('Modelli')
ax.set_ylabel('Accuracy')
ax.set_title('Confronto Performance Algoritmi di Classificazione')
ax.set_xticks(x)
ax.set_xticklabels(results_df['Model'], rotation=45, ha='right')
ax.legend(loc='lower right')
ax.grid(True, alpha=0.3, axis='y')

# Aggiungi valori sulle barre
for bars in [bars1, bars2, bars3]:
    for bar in bars:
        height = bar.get_height()
        ax.annotate(f'{height:.3f}',
                   xy=(bar.get_x() + bar.get_width() / 2, height),
                   xytext=(0, 3),  # 3 points vertical offset
                   textcoords="offset points",
                   ha='center', va='bottom', fontsize=9)

plt.tight_layout()
plt.show()

print("✅ Addestramento e valutazione modelli completati!")

Parte 5: Analisi Dettagliata e Utilizzo Pratico

▶ Analisi Modello Migliore e Previsioni

6
Analizza il miglior modello e usalo per previsioni:
PYTHON
# 6. ANALISI DETTAGLIATA MODELLO MIGLIORE
print("🏆 ANALISI MODELLO MIGLIORE: RANDOM FOREST")
print("="*60)

# Seleziona il modello migliore (Random Forest in questo caso)
best_model_name = results_df.iloc[0]['Model']
best_model = models[best_model_name]

print(f"Modello selezionato: {best_model_name}")
print(f"Test Accuracy: {results_df.iloc[0]['Test Accuracy']:.3f}")

# 6.1 Matrice di confusione dettagliata
print(f"\n📊 MATRICE DI CONFUSIONE DETTAGLIATA:")

y_pred_best = best_model.predict(X_test_scaled)
cm = confusion_matrix(y_test, y_pred_best)

# Visualizzazione matrice di confusione
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', 
            xticklabels=target_names, yticklabels=target_names)
plt.title(f'Matrice di Confusione - {best_model_name}', fontsize=16, pad=20)
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.tight_layout()
plt.show()

# 6.2 Classification report
print(f"\n📋 CLASSIFICATION REPORT:")
cr = classification_report(y_test, y_pred_best, target_names=target_names)
print(cr)

# 6.3 Feature importance (solo per Random Forest e Decision Tree)
if hasattr(best_model, 'feature_importances_'):
    print(f"\n🔍 FEATURE IMPORTANCE:")
    importances = best_model.feature_importances_
    feature_importance_df = pd.DataFrame({
        'Feature': feature_names,
        'Importance': importances
    }).sort_values('Importance', ascending=False)
    
    print(feature_importance_df.to_string(index=False))
    
    # Visualizzazione feature importance
    plt.figure(figsize=(10, 6))
    bars = plt.barh(feature_importance_df['Feature'], feature_importance_df['Importance'], 
                   color='steelblue')
    plt.xlabel('Importance')
    plt.title(f'Feature Importance - {best_model_name}', fontsize=14)
    plt.gca().invert_yaxis()  # Mostra la feature più importante in alto
    
    # Aggiungi valori sulle barre
    for bar in bars:
        width = bar.get_width()
        plt.text(width + 0.001, bar.get_y() + bar.get_height()/2, 
                f'{width:.3f}', va='center', fontsize=10)
    
    plt.tight_layout()
    plt.show()

# 6.4 Esempi di previsioni sul test set
print(f"\n🔮 ESEMPI DI PREVISIONI SUL TEST SET:")
print("="*50)

# Seleziona alcuni esempi dal test set
sample_indices = np.random.choice(len(X_test), 10, replace=False)

print("\n{:^5} | {:^25} | {:^25} | {:^8}".format(
    "IDX", "Caratteristiche Reali", "Predizione", "Corretto?"))
print("-" * 70)

for idx in sample_indices:
    features_real = X_test[idx]
    features_scaled = X_test_scaled[idx]
    true_label = y_test[idx]
    pred_label = best_model.predict([features_scaled])[0]
    pred_proba = best_model.predict_proba([features_scaled])[0]
    
    # Formatta le caratteristiche
    features_str = f"SL:{features_real[0]:.1f}, SW:{features_real[1]:.1f}, PL:{features_real[2]:.1f}, PW:{features_real[3]:.1f}"
    
    # Formatta predizione con probabilità
    pred_name = target_names[pred_label]
    true_name = target_names[true_label]
    proba = pred_proba[pred_label] * 100
    
    correct = "✅" if pred_label == true_label else "❌"
    
    print("{:^5} | {:^25} | {:^25} | {:^8}".format(
        idx, features_str, f"{pred_name} ({proba:.1f}%)", correct))

# 6.5 Previsioni su nuovi dati (fiori sconosciuti)
print(f"\n🌺 PREVISIONI SU NUOVI FIORI SCONOSCIUTI:")
print("="*50)

# Crea nuovi fiori "sconosciuti" per la classificazione
nuovi_fiori = np.array([
    [5.1, 3.5, 1.4, 0.2],  # Sembra una setosa
    [6.0, 2.9, 4.5, 1.5],  # Sembra una versicolor
    [7.2, 3.0, 5.8, 2.1],  # Sembra una virginica
    [5.8, 2.7, 3.9, 1.2],  # Caso intermedio
    [6.7, 3.1, 5.6, 2.4]   # Caso estremo
])

# Normalizza i nuovi dati
nuovi_fiori_scaled = scaler.transform(nuovi_fiori)

# Fai previsioni
predizioni = best_model.predict(nuovi_fiori_scaled)
probabilita = best_model.predict_proba(nuovi_fiori_scaled)

print("\n{:^5} | {:^30} | {:^20} | {:^20}".format(
    "Fiore", "Caratteristiche (SL,SW,PL,PW)", "Specie Predetta", "Probabilità"))
print("-" * 90)

for i, (fiore, pred, prob) in enumerate(zip(nuovi_fiori, predizioni, probabilita)):
    caratteristiche = f"{fiore[0]:.1f}, {fiore[1]:.1f}, {fiore[2]:.1f}, {fiore[3]:.1f}"
    specie_predetta = target_names[pred]
    prob_max = prob[pred] * 100
    
    # Mostra anche le altre probabilità
    altre_probab = ", ".join([f"{target_names[j]}: {prob[j]*100:.1f}%" 
                            for j in range(3) if j != pred])
    
    print("{:^5} | {:^30} | {:^20} | {:^20}".format(
        f"F{i+1}", caratteristiche, specie_predetta, f"{prob_max:.1f}%"))
    print("{:^5} | {:^30} | {:^20} | {:^20}".format(
        "", "", "", f"Altro: {altre_probab}"))

print(f"\n✅ Sistema di classificazione Iris completato con successo!")
print(f"🎯 Il modello {best_model_name} classifica correttamente il {results_df.iloc[0]['Test Accuracy']*100:.1f}% dei fiori!")

Concetti di Classificazione ML Appresi

Congratulazioni! Ora conosci:

  • Classificazione ML: Algoritmi per categorizzare dati in classi
  • Dataset Iris: Il benchmark standard per classificazione
  • Algoritmi Multipli: KNN, SVM, Decision Tree, Random Forest, Naive Bayes
  • StandardScaler: Normalizzazione features per ML
  • Stratified Split: Mantenere distribuzione classi in train/test
  • Metriche di Valutazione: Accuracy, Confusion Matrix, Classification Report
  • Cross-Validation: Valutazione robusta dei modelli
  • Feature Importance: Importanza delle variabili nei modelli
  • Predizioni Probabilistiche: Probabilità associate a ogni classe

Prossimi Passi nella Classificazione ML

Nella prossima esercitazione imparerai:

  • 🔍 Clustering con K-Means e DBSCAN
  • 📊 Classificazione multi-classe avanzata
  • 🤖 Ensemble methods e voting classifiers
  • 🧠 Reti neurali per classificazione immagini
  • 🎯 Hyperparameter tuning con GridSearch

Hai padroneggiato le basi della classificazione con Machine Learning!

Torna in alto