Osserviamo i dati per capire pattern, relazioni e insights nascosti.
🚫 COPIA BLOCCATA
# ============================================================================
# PROGETTO FINALE: FASE 2 - ANALISI ESPLORATIVA DEI DATI (EDA)
# ============================================================================
print("🔍 PROGETTO FINALE - FASE 2: ANALISI ESPLORATIVA (EDA)")
print("=" * 80)
print("🎯 OBIETTIVO: Capire i dati, trovare pattern e prepararsi per il ML")
print("=" * 80)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
# Configurazione grafica per Google Colab
plt.style.use('seaborn-v0_8-darkgrid')
sns.set_palette("husl")
# ------------------------------------------------------------
# PASSO 1: CARICAMENTO DATI PULITI
# ------------------------------------------------------------
print("\n\n📥 PASSO 1: CARICAMENTO DATI PULITI DELLA FASE 1")
print("-" * 50)
try:
df = pd.read_csv('case_pulite.csv')
print("✅ Dataset 'case_pulite.csv' caricato con successo!")
except:
print("⚠️ File non trovato. Ricreiamo i dati dalla Fase 1...")
# Se il file non esiste, ricreiamo i dati (semplificato)
np.random.seed(42)
n = 550
df = pd.DataFrame({
'metratura': np.clip(np.random.normal(120, 40, n), 50, 300),
'camere': np.random.choice([2, 3, 4, 5], n, p=[0.3, 0.4, 0.2, 0.1]),
'bagni': np.clip(np.random.normal(2, 0.8, n), 1, 5),
'eta_reale': np.clip(np.random.exponential(25, n), 0, 100),
'distanza_centro': np.random.uniform(1, 20, n),
'prezzo': np.random.normal(300000, 80000, n),
'quartiere': np.random.choice(['Centro', 'Periferia', 'Residenziale', 'Commerciale'], n),
'giardino': np.random.choice([True, False], n),
'box_auto': np.random.choice([0, 1], n),
'classe_energetica': np.random.choice(['A', 'B', 'C', 'D', 'E'], n, p=[0.1, 0.2, 0.3, 0.3, 0.1])
})
print(f"\n📊 DIMENSIONI DATASET: {df.shape[0]} case × {df.shape[1]} caratteristiche")
print("\n🔍 PRIME 5 CASE:")
print(df.head())
# ------------------------------------------------------------
# PASSO 2: ANALISI UNIVARIATA (UNA VARIABILE ALLA VOLTA)
# ------------------------------------------------------------
print("\n\n📊 PASSO 2: ANALISI UNIVARIATA - DISTRIBUZIONI")
print("-" * 50)
print("Analizziamo la distribuzione di ogni variabile importante:")
# 1. PREZZO (VARIABILE TARGET)
print("\n1. 💰 DISTRIBUZIONE PREZZI:")
prezzo_stats = df['prezzo'].describe()
print(prezzo_stats)
print(f"\n📈 INSIGHTS PREZZO:")
print(f"• Media: €{prezzo_stats['mean']:,.0f}")
print(f"• Mediana: €{prezzo_stats['50%']:,.0f}")
print(f"• Range: €{prezzo_stats['min']:,.0f} - €{prezzo_stats['max']:,.0f}")
print(f"• IQR: €{prezzo_stats['25%']:,.0f} - €{prezzo_stats['75%']:,.0f}")
# Test normalità
stat, p_value = stats.shapiro(df['prezzo'].sample(min(5000, len(df))))
print(f"• Test normalità (Shapiro-Wilk): p-value = {p_value:.4f}")
if p_value > 0.05:
print(" ✅ I prezzi seguono una distribuzione normale")
else:
print(" ⚠️ I prezzi NON seguono una distribuzione normale")
# 2. METRATURA
print("\n2. 🏠 DISTRIBUZIONE METRATURA:")
print(df['metratura'].describe())
# 3. CAMERE
print("\n3. 🚪 DISTRIBUZIONE NUMERO CAMERE:")
print(df['camere'].value_counts().sort_index())
print(f"\nModa: {df['camere'].mode()[0]} camere")
# 4. ETÀ
print("\n4. 🕰️ DISTRIBUZIONE ETÀ CASE:")
print(df['eta_reale'].describe())
print("\n📈 SU GOOGLE COLAB, SCOMMENTA PER I GRAFICI DI DISTRIBUZIONE:")
"""
# Creiamo subplot per distribuzioni
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
fig.suptitle('Distribuzioni Variabili Principali', fontsize=16)
# 1. Prezzo
axes[0, 0].hist(df['prezzo'], bins=30, edgecolor='black', alpha=0.7)
axes[0, 0].set_xlabel('Prezzo (€)')
axes[0, 0].set_ylabel('Frequenza')
axes[0, 0].set_title('Distribuzione Prezzi')
axes[0, 0].axvline(df['prezzo'].mean(), color='red', linestyle='--', label='Media')
axes[0, 0].axvline(df['prezzo'].median(), color='green', linestyle='--', label='Mediana')
axes[0, 0].legend()
# 2. Metratura
axes[0, 1].hist(df['metratura'], bins=30, edgecolor='black', alpha=0.7, color='orange')
axes[0, 1].set_xlabel('Metratura (m²)')
axes[0, 1].set_ylabel('Frequenza')
axes[0, 1].set_title('Distribuzione Metrature')
# 3. Camere
camere_counts = df['camere'].value_counts().sort_index()
axes[0, 2].bar(camere_counts.index, camere_counts.values, color='green', alpha=0.7)
axes[0, 2].set_xlabel('Numero Camere')
axes[0, 2].set_ylabel('Numero Case')
axes[0, 2].set_title('Distribuzione Camere')
axes[0, 2].set_xticks(camere_counts.index)
# 4. Età
axes[1, 0].hist(df['eta_reale'], bins=30, edgecolor='black', alpha=0.7, color='purple')
axes[1, 0].set_xlabel('Età (anni)')
axes[1, 0].set_ylabel('Frequenza')
axes[1, 0].set_title('Distribuzione Età Case')
# 5. Bagni
bagni_counts = (df['bagni'] * 2).astype(int).value_counts().sort_index()
axes[1, 1].bar([x/2 for x in bagni_counts.index], bagni_counts.values, color='brown', alpha=0.7)
axes[1, 1].set_xlabel('Numero Bagni')
axes[1, 1].set_ylabel('Numero Case')
axes[1, 1].set_title('Distribuzione Bagni')
# 6. Distanza centro
axes[1, 2].hist(df['distanza_centro'], bins=30, edgecolor='black', alpha=0.7, color='blue')
axes[1, 2].set_xlabel('Distanza Centro (km)')
axes[1, 2].set_ylabel('Frequenza')
axes[1, 2].set_title('Distribuzione Distanza dal Centro')
plt.tight_layout()
plt.show()
"""
# ------------------------------------------------------------
# PASSO 3: ANALISI BIVARIATA (RELAZIONI TRA VARIABILI)
# ------------------------------------------------------------
print("\n\n📈 PASSO 3: ANALISI BIVARIATA - CORRELAZIONI")
print("-" * 50)
print("Analizziamo come le variabili si relazionano tra loro:")
# 1. CORRELAZIONI NUMERICHE
print("\n1. 🔗 MATRICE DI CORRELAZIONE (VARIABILI NUMERICHE):")
numeric_cols = ['prezzo', 'metratura', 'camere', 'bagni', 'eta_reale', 'distanza_centro']
corr_matrix = df[numeric_cols].corr()
print("\nCorrelazioni con il PREZZO (obiettivo):")
prezzo_corr = corr_matrix['prezzo'].sort_values(ascending=False)
for var, corr in prezzo_corr.items():
if var != 'prezzo':
direzione = "positiva" if corr > 0 else "negativa"
forza = "forte" if abs(corr) > 0.5 else "moderata" if abs(corr) > 0.3 else "debole"
print(f"• {var:15} : {corr:6.3f} ({forza} {direzione})")
print("\n🎯 INTERPRETAZIONE CORRELAZIONI:")
print("• Metratura: Più grande la casa, più alto il prezzo")
print("• Camere: Più camere, prezzo più alto")
print("• Bagni: Più bagni, prezzo più alto")
print("• Età: Case più vecchie costano meno")
print("• Distanza: Più lontano dal centro, prezzo più basso")
print("\n📊 SU GOOGLE COLAB, SCOMMENTA PER MATRICE DI CORRELAZIONE:")
"""
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0, fmt='.2f',
square=True, linewidths=1, cbar_kws={"shrink": 0.8})
plt.title('Matrice di Correlazione - Variabili Numeriche', fontsize=16)
plt.tight_layout()
plt.show()
"""
# 2. SCATTER PLOTS (RELAZIONI IMPORTANTI)
print("\n2. 📊 SCATTER PLOTS - RELAZIONI CHIAVE")
print("\n📈 SU GOOGLE COLAB, SCOMMENTA PER SCATTER PLOTS:")
"""
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Relazioni tra Prezzo e Altre Variabili', fontsize=16)
# Prezzo vs Metratura
axes[0, 0].scatter(df['metratura'], df['prezzo'], alpha=0.5, s=20)
axes[0, 0].set_xlabel('Metratura (m²)')
axes[0, 0].set_ylabel('Prezzo (€)')
axes[0, 0].set_title('Prezzo vs Metratura')
axes[0, 0].grid(True, alpha=0.3)
# Prezzo vs Camere
axes[0, 1].scatter(df['camere'], df['prezzo'], alpha=0.5, s=20)
axes[0, 1].set_xlabel('Numero Camere')
axes[0, 1].set_ylabel('Prezzo (€)')
axes[0, 1].set_title('Prezzo vs Camere')
axes[0, 1].grid(True, alpha=0.3)
# Prezzo vs Età
axes[1, 0].scatter(df['eta_reale'], df['prezzo'], alpha=0.5, s=20)
axes[1, 0].set_xlabel('Età Casa (anni)')
axes[1, 0].set_ylabel('Prezzo (€)')
axes[1, 0].set_title('Prezzo vs Età')
axes[1, 0].grid(True, alpha=0.3)
# Prezzo vs Distanza
axes[1, 1].scatter(df['distanza_centro'], df['prezzo'], alpha=0.5, s=20)
axes[1, 1].set_xlabel('Distanza Centro (km)')
axes[1, 1].set_ylabel('Prezzo (€)')
axes[1, 1].set_title('Prezzo vs Distanza dal Centro')
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
"""
# ------------------------------------------------------------
# PASSO 4: ANALISI VARIABILI CATEGORICHE
# ------------------------------------------------------------
print("\n\n🏙️ PASSO 4: ANALISI VARIABILI CATEGORICHE")
print("-" * 50)
# 1. QUARTIERE vs PREZZO
print("\n1. 🏙️ QUARTIERE vs PREZZO:")
quartiere_stats = df.groupby('quartiere')['prezzo'].agg(['mean', 'median', 'count', 'std'])
print(quartiere_stats.round(0))
print("\n📊 DIFFERENZE TRA QUARTIERI:")
for quartiere in quartiere_stats.index:
prezzo_medio = quartiere_stats.loc[quartiere, 'mean']
diff_dalla_media = prezzo_medio - df['prezzo'].mean()
percentuale = (diff_dalla_media / df['prezzo'].mean()) * 100
segno = "+" if percentuale > 0 else ""
print(f"• {quartiere:15}: €{prezzo_medio:,.0f} ({segno}{percentuale:.1f}% dalla media)")
# 2. GIARDINO vs PREZZO
print("\n2. 🌳 GIARDINO vs PREZZO:")
giardino_stats = df.groupby('giardino')['prezzo'].mean()
print(giardino_stats.round(0))
diff_giardino = giardino_stats[True] - giardino_stats[False]
percentuale_giardino = (diff_giardino / giardino_stats[False]) * 100
print(f"📈 Differenza: €{diff_giardino:,.0f} (+{percentuale_giardino:.1f}%)")
# 3. CLASSE ENERGETICA vs PREZZO
print("\n3. ⚡ CLASSE ENERGETICA vs PREZZO:")
classe_stats = df.groupby('classe_energetica')['prezzo'].mean().sort_index()
print(classe_stats.round(0))
print("\n📈 SU GOOGLE COLAB, SCOMMENTA PER BOXPLOT CATEGORICI:")
"""
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
fig.suptitle('Analisi Variabili Categoriche', fontsize=16)
# Quartiere
sns.boxplot(x='quartiere', y='prezzo', data=df, ax=axes[0])
axes[0].set_title('Prezzo per Quartiere')
axes[0].tick_params(axis='x', rotation=45)
axes[0].set_ylabel('Prezzo (€)')
# Giardino
sns.boxplot(x='giardino', y='prezzo', data=df, ax=axes[1])
axes[1].set_title('Prezzo con/senza Giardino')
axes[1].set_ylabel('Prezzo (€)')
# Classe energetica
sns.boxplot(x='classe_energetica', y='prezzo', data=df, ax=axes[2])
axes[2].set_title('Prezzo per Classe Energetica')
axes[2].set_ylabel('Prezzo (€)')
plt.tight_layout()
plt.show()
"""
# ------------------------------------------------------------
# PASSO 5: ANALISI MULTIVARIATA AVANZATA
# ------------------------------------------------------------
print("\n\n🔬 PASSO 5: ANALISI MULTIVARIATA AVANZATA")
print("-" * 50)
print("Analizziamo interazioni complesse tra variabili:")
# 1. INTERAZIONE: QUARTIERE × METRATURA
print("\n1. 🏙️ × 🏠 QUARTIERE × METRATURA:")
# Calcoliamo prezzo per m² per quartiere
df['prezzo_per_m2'] = df['prezzo'] / df['metratura']
prezzo_m2_per_quartiere = df.groupby('quartiere')['prezzo_per_m2'].mean().sort_values(ascending=False)
print("💰 PREZZO PER METRO QUADRO PER QUARTIERE:")
for quartiere, prezzo_m2 in prezzo_m2_per_quartiere.items():
print(f"• {quartiere:15}: €{prezzo_m2:,.0f}/m²")
# 2. INTERAZIONE: ETÀ × RISTRUTTURAZIONE IMMAGINARIA
print("\n2. 🕰️ × 🔨 ETÀ × VALORE:")
# Creiamo una feature: case "giovani" con giardino valgono di più?
df['categoria_eta'] = pd.cut(df['eta_reale'],
bins=[0, 10, 30, 50, 100],
labels=['Nuova (<10)', 'Media (10-30)', 'Vecchia (30-50)', 'Molto Vecchia (>50)'])
eta_giardino_stats = df.groupby(['categoria_eta', 'giardino'])['prezzo'].mean().unstack()
print("\n💰 PREZZO MEDIO PER ETÀ E GIARDINO:")
print(eta_giardino_stats.round(0))
# ------------------------------------------------------------
# PASSO 6: IDENTIFICAZIONE PATTERN E INSIGHTS
# ------------------------------------------------------------
print("\n\n🎯 PASSO 6: INSIGHTS E CONCLUSIONI EDA")
print("-" * 50)
print("📊 INSIGHTS PRINCIPALI TROVATI:")
print("\n1. 🏆 VARIABILI PIÙ IMPORTANTI PER IL PREZZO:")
print(" • Metratura (corr: {:.3f})".format(corr_matrix.loc['metratura', 'prezzo']))
print(" • Numero camere (corr: {:.3f})".format(corr_matrix.loc['camere', 'prezzo']))
print(" • Distanza dal centro (corr: {:.3f})".format(corr_matrix.loc['distanza_centro', 'prezzo']))
print(" • Età casa (corr: {:.3f})".format(corr_matrix.loc['eta_reale', 'prezzo']))
print("\n2. 🏙️ EFFETTO QUARTIERE:")
quartiere_piu_caro = quartiere_stats['mean'].idxmax()
quartiere_meno_caro = quartiere_stats['mean'].idxmin()
differenza = quartiere_stats.loc[quartiere_piu_caro, 'mean'] - quartiere_stats.loc[quartiere_meno_caro, 'mean']
print(f" • Quartiere più caro: {quartiere_piu_caro} (€{quartiere_stats.loc[quartiere_piu_caro, 'mean']:,.0f})")
print(f" • Quartiere meno caro: {quartiere_meno_caro} (€{quartiere_stats.loc[quartiere_meno_caro, 'mean']:,.0f})")
print(f" • Differenza: €{differenza:,.0f}")
print("\n3. 🌳 VALORE AGGIUNTO GIARDINO:")
print(f" • Con giardino: €{giardino_stats[True]:,.0f}")
print(f" • Senza giardino: €{giardino_stats[False]:,.0f}")
print(f" • Valore aggiunto: €{diff_giardino:,.0f} (+{percentuale_giardino:.1f}%)")
print("\n4. ⚡ EFFETTO CLASSE ENERGETICA:")
classe_migliore = classe_stats.idxmax()
classe_peggiore = classe_stats.idxmin()
print(f" • Classe migliore ({classe_migliore}): €{classe_stats.max():,.0f}")
print(f" • Classe peggiore ({classe_peggiore}): €{classe_stats.min():,.0f}")
print(f" • Differenza: €{classe_stats.max() - classe_stats.min():,.0f}")
print("\n5. 📈 PATTERN INTERESSANTI:")
print(" • Case nel centro valgono di più per m²")
print(" • Il giardino aggiunge più valore alle case vecchie")
print(" • Le case con 3 camere sono le più comuni (moda)")
print(" • La relazione prezzo-metratura è quasi lineare")
# ------------------------------------------------------------
# PASSO 7: PREPARAZIONE PER IL MACHINE LEARNING
# ------------------------------------------------------------
print("\n\n🤖 PASSO 7: PREPARAZIONE PER IL MACHINE LEARNING")
print("-" * 50)
print("Basandoci sull'EDA, decidiamo cosa fare per il ML:")
print("\n🎯 FEATURE SELECTION (BASATA SU EDA):")
print("✅ INCLUSE:")
print(" • Metratura (molto importante)")
print(" • Numero camere (molto importante)")
print(" • Distanza centro (importante)")
print(" • Età casa (importante)")
print(" • Quartiere (categorica, encoding necessario)")
print(" • Giardino (booleano, valore aggiunto)")
print(" • Bagni (correlato con camere, ma utile)")
print(" • Classe energetica (categorica, encoding)")
print("\n⚠️ CONSIDERAZIONI:")
print(" • Metratura e camere sono correlate (multicollinearità)")
print(" • Età e anno costruzione sono ridondanti (scegliamo età)")
print(" • Box auto ha poche variazioni (potrebbe essere meno utile)")
print("\n🔧 PREPROCESSING NECESSARIO:")
print(" • Encoding variabili categoriche (One-Hot per quartiere e classe)")
print(" • Scaling variabili numeriche (tutte tranne quelle binarie)")
print(" • Gestione outliers (già fatto in Fase 1)")
print(" • Train/Test split (80/20 o 70/30)")
# ------------------------------------------------------------
# PASSO 8: SALVATAGGIO INSIGHTS E DATI PREPARATI
# ------------------------------------------------------------
print("\n\n💾 PASSO 8: SALVATAGGIO INSIGHTS E DATI PER ML")
print("-" * 50)
# Salva insights principali
insights = {
'n_case': len(df),
'prezzo_medio': df['prezzo'].mean(),
'correlazioni': corr_matrix['prezzo'].to_dict(),
'quartieri': quartiere_stats.to_dict(),
'giardino_effect': diff_giardino,
'classe_effect': (classe_stats.max() - classe_stats.min())
}
import json
with open('eda_insights.json', 'w') as f:
json.dump(insights, f, indent=2, default=str)
print("✅ Insights salvati in 'eda_insights.json'")
# Salva dati pronti per ML (senza preprocessing, solo selezione)
ml_features = ['metratura', 'camere', 'bagni', 'eta_reale', 'distanza_centro',
'quartiere', 'giardino', 'classe_energetica', 'prezzo']
df_ml_ready = df[ml_features].copy()
df_ml_ready.to_csv('dati_pronti_ml.csv', index=False)
print("✅ Dati pronti per ML salvati in 'dati_pronti_ml.csv'")
# ------------------------------------------------------------
# RIEPILOGO FASE 2
# ------------------------------------------------------------
print("\n\n🎉 FASE 2 (EDA) COMPLETATA CON SUCCESSO!")
print("=" * 50)
print("\n✅ COSA ABBIAMO FATTO:")
print("1. Analizzato distribuzioni di tutte le variabili")
print("2. Studiato correlazioni tra variabili numeriche")
print("3. Analizzato l'effetto delle variabili categoriche")
print("4. Identificato pattern e interazioni complesse")
print("5. Estratto insights importanti per il business")
print("6. Deciso le feature per il modello ML")
print("7. Salvato insights e dati preparati")
print("\n🎯 INSIGHTS CHIAVE PER IL MODELLO ML:")
print(f"• La metratura spiega il {corr_matrix.loc['metratura', 'prezzo']**2*100:.1f}% della varianza del prezzo")
print(f"• Il quartiere causa differenze fino a €{differenza:,.0f}")
print(f"• Il giardino aggiunge +{percentuale_giardino:.1f}% di valore")
print(f"• La classe energetica fa differenze fino a €{classe_stats.max() - classe_stats.min():,.0f}")
print("\n🚀 PRONTI PER LA FASE 3: MODELLAZIONE ML!")
print("Nel prossimo passo creeremo e alleneremo modelli di Machine Learning.")
# Statistiche finali per riferimento
print("\n📊 STATISTICHE FINALI DATASET:")
print(f"• Numero case: {len(df)}")
print(f"• Prezzo medio: €{df['prezzo'].mean():,.0f}")
print(f"• Metratura media: {df['metratura'].mean():.0f} m²")
print(f"• Età media: {df['eta_reale'].mean():.0f} anni")
print(f"• Distanza media dal centro: {df['distanza_centro'].mean():.1f} km")