CLASSE QUARTA • REGRESSIONE LINEARE

Regressione Lineare

Dalla teoria alla pratica: predici valori continui come un data scientist

Dalle categorie ai numeri! Dopo la classificazione, esploriamo la regressione lineare: l'algoritmo ML più semplice ma potente per predire valori continui.

📚 Teoria della Regressione Lineare

Formula della Regressione Lineare Semplice:
y = β₀ + β₁x + ε
Dove:
y = variabile dipendente (da predire)
x = variabile indipendente (predittore)
β₀ = intercetta (bias)
β₁ = coefficiente angolare (pendenza)
ε = errore (residuo)
X (Predittore)
Y (Target)

1. Linearità

La relazione tra X e Y deve essere lineare.

✅ Verifica: Scatter plot

2. Indipendenza errori

Gli errori (residui) devono essere indipendenti.

✅ Verifica: Durbin-Watson test

3. Omoschedasticità

Varianza costante degli errori.

❌ Violazione comune: Funnel pattern

4. Normalità errori

Gli errori devono seguire distribuzione normale.

✅ Verifica: QQ-plot, Shapiro-Wilk

🎯 Obiettivo della Regressione Lineare

Trovare la retta che minimizza la somma dei quadrati degli errori (Ordinary Least Squares - OLS):

min Σ(yᵢ - ŷᵢ)²

Dove ŷᵢ sono i valori predetti dalla retta di regressione.

🔧 Regressione Lineare con Scikit-learn

Passiamo dalla teoria alla pratica con un esempio completo.

🚫 COPIA BLOCCATA
# REGRESSIONE LINEARE COMPLETA - CASO PRATICO: PREZZI CASE import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split, cross_val_score from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score from sklearn.preprocessing import StandardScaler import scipy.stats as stats print("🏠 REGRESSIONE LINEARE - PREZZI CASE") print("=" * 70) # 1. CREAZIONE DATASET SINTETICO (simuliamo dati reali) np.random.seed(42) n_samples = 500 # Features realistiche per case metratura = np.random.normal(120, 40, n_samples) # Metratura in m² metratura = np.clip(metratura, 50, 250) # Min 50m², max 250m² num_camere = np.random.poisson(3, n_samples) # Numero camere (media 3) num_camere = np.clip(num_camere, 1, 6) # Min 1, max 6 camere eta_casa = np.random.exponential(20, n_samples) # Età casa in anni eta_casa = np.clip(eta_casa, 0, 60) # Max 60 anni distanza_centro = np.random.exponential(5, n_samples) # Distanza centro in km distanza_centro = np.clip(distanza_centro, 1, 20) # Prezzo base (€/m²) prezzo_base = 3000 # Formula prezzo con relazioni realistiche prezzo = ( prezzo_base * metratura * 0.8 + # Metratura principale 50000 * num_camere + # Ogni camera aggiunge valore -2000 * eta_casa + # Case vecchie valgono meno -10000 * distanza_centro + # Più lontano = meno valore np.random.normal(0, 50000, n_samples) # Rumore/variazione ) # Crea DataFrame df_case = pd.DataFrame({ 'metratura': metratura, 'num_camere': num_camere, 'eta_casa': eta_casa, 'distanza_centro': distanza_centro, 'prezzo': prezzo }) # Assicuriamoci prezzi positivi df_case['prezzo'] = np.clip(df_case['prezzo'], 100000, 1000000) print("\n1. 📊 DATASET CASE (prime 10 righe):") print(df_case.head(10)) print(f"\n📈 DIMENSIONI: {df_case.shape}") print(f"💰 PREZZO MEDIO: €{df_case['prezzo'].mean():,.0f}") print(f"📏 METRATURA MEDIA: {df_case['metratura'].mean():.0f} m²") # 2. ANALISI ESPLORATIVA (EDA) print("\n\n2. 🔍 ANALISI ESPLORATIVA DEI DATI") print("-" * 40) print("\n📋 STATISTICHE DESCRITTIVE:") print(df_case.describe()) print("\n📊 MATRICE DI CORRELAZIONE:") correlation_matrix = df_case.corr() print(correlation_matrix.round(3)) print("\n🎯 CORRELAZIONI CON PREZZO:") prezzo_corr = correlation_matrix['prezzo'].sort_values(ascending=False) print(prezzo_corr) print("\n📈 SU GOOGLE COLAB, SCOMMENTA PER VEDERE I GRAFICI:") """ # Pairplot per vedere tutte le relazioni sns.pairplot(df_case, diag_kind='kde') plt.suptitle('Analisi Multivariata - Dataset Case', y=1.02) plt.show() # Scatter plot prezzo vs metratura plt.figure(figsize=(10, 6)) sns.scatterplot(x='metratura', y='prezzo', data=df_case, alpha=0.6) plt.title('Prezzo vs Metratura') plt.xlabel('Metratura (m²)') plt.ylabel('Prezzo (€)') plt.grid(True, alpha=0.3) plt.show() # Matrice di correlazione heatmap plt.figure(figsize=(8, 6)) sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0, fmt='.2f') plt.title('Matrice di Correlazione') plt.show() """ # 3. PREPARAZIONE DATI PER ML print("\n\n3. 🛠️ PREPARAZIONE DATI PER REGRESSIONE") print("-" * 40) # Separazione features (X) e target (y) X = df_case[['metratura', 'num_camere', 'eta_casa', 'distanza_centro']] y = df_case['prezzo'] print(f"Features shape: {X.shape}") print(f"Target shape: {y.shape}") # Standardizzazione delle features scaler = StandardScaler() X_scaled = scaler.fit_transform(X) print("✅ Features standardizzate (media=0, dev std=1)") # Train/Test split X_train, X_test, y_train, y_test = train_test_split( X_scaled, y, test_size=0.2, # 20% test random_state=42 ) print(f"\n🎯 SPLIT DATI:") print(f"Training set: {X_train.shape[0]} case ({X_train.shape[0]/len(X)*100:.0f}%)") print(f"Test set: {X_test.shape[0]} case ({X_test.shape[0]/len(X)*100:.0f}%)") # 4. TRAINING MODELLO DI REGRESSIONE LINEARE print("\n\n4. 🤖 TRAINING MODELLO REGRESSIONE LINEARE") print("-" * 40) # Crea e addestra modello model = LinearRegression() model.fit(X_train, y_train) print("✅ Modello addestrato!") print(f"\n🎯 COEFFICIENTI DEL MODELLO:") # Mostra coefficienti in modo leggibile features = ['metratura', 'num_camere', 'eta_casa', 'distanza_centro'] for feature, coef in zip(features, model.coef_): print(f" {feature:20} : {coef:10,.0f} €") print(f"\n📐 INTERCETTA (β₀): {model.intercept_:,.0f} €") # Interpretazione coefficienti print("\n📖 INTERPRETAZIONE COEFFICIENTI:") print("Per ogni aumento di 1 deviazione standard...") print(f"• Metratura: +{model.coef_[0]:,.0f} € al prezzo") print(f"• Numero camere: +{model.coef_[1]:,.0f} € al prezzo") print(f"• Età casa: {model.coef_[2]:,.0f} € al prezzo (negativo = svaluta)") print(f"• Distanza centro: {model.coef_[3]:,.0f} € al prezzo (negativo = svaluta)") # 5. PREDIZIONI E VALUTAZIONE print("\n\n5. 🔮 PREDIZIONI E VALUTAZIONE MODELLO") print("-" * 40) # Predizioni sul test set y_pred = model.predict(X_test) # Calcola tutte le metriche mse = mean_squared_error(y_test, y_pred) rmse = np.sqrt(mse) mae = mean_absolute_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print(f"📊 PERFORMANCE SUL TEST SET:") print(f"🎯 Mean Squared Error (MSE): {mse:,.0f}") print(f"🎯 Root Mean Squared Error (RMSE): {rmse:,.0f} €") print(f"🎯 Mean Absolute Error (MAE): {mae:,.0f} €") print(f"🎯 R² Score (Coefficiente di Determinazione): {r2:.3f}") # Interpretazione RMSE e MAE prezzo_medio = y_test.mean() print(f"\n📈 INTERPRETAZIONE:") print(f"Prezzo medio test set: €{prezzo_medio:,.0f}") print(f"RMSE/Prezzo medio: {(rmse/prezzo_medio*100):.1f}%") print(f"MAE/Prezzo medio: {(mae/prezzo_medio*100):.1f}%") # Interpretazione R² print(f"\n📊 INTERPRETAZIONE R²:") print(f"Il modello spiega il {r2*100:.1f}% della varianza nei prezzi") if r2 > 0.7: print("✅ Ottimo fit del modello!") elif r2 > 0.5: print("⚠️ Fit moderato - potrebbero servire più features") else: print("❌ Fit scarso - il modello non cattura bene la relazione") # 6. ANALISI DEI RESIDUI print("\n\n6. 📉 ANALISI DEI RESIDUI (ERRORI)") print("-" * 40) # Calcola residui residuals = y_test - y_pred print(f"📊 STATISTICHE RESIDUI:") print(f"Media residui: €{residuals.mean():,.0f} (dovrebbe essere vicina a 0)") print(f"Deviazione standard residui: €{residuals.std():,.0f}") print(f"Min residuo: €{residuals.min():,.0f} (sovrastima più grande)") print(f"Max residuo: €{residuals.max():,.0f} (sottostima più grande)") # Test normalità residui (Shapiro-Wilk) shapiro_stat, shapiro_p = stats.shapiro(residuals[:1000]) # Shapiro max 5000 campioni print(f"\n🎯 TEST NORMALITÀ RESIDUI (Shapiro-Wilk):") print(f"Statistica: {shapiro_stat:.3f}, p-value: {shapiro_p:.4f}") if shapiro_p > 0.05: print("✅ Non possiamo rifiutare normalità dei residui") else: print("⚠️ I residui potrebbero non essere normali") print("\n📈 SU GOOGLE COLAB, SCOMMENTA PER ANALISI GRAFICA RESIDUI:") """ # Plot residui vs predetti plt.figure(figsize=(12, 10)) plt.subplot(2, 2, 1) plt.scatter(y_pred, residuals, alpha=0.6) plt.axhline(y=0, color='red', linestyle='--') plt.xlabel('Prezzo Predetto (€)') plt.ylabel('Residui (€)') plt.title('Residui vs Predetti') plt.grid(True, alpha=0.3) plt.subplot(2, 2, 2) stats.probplot(residuals, dist="norm", plot=plt) plt.title('QQ-Plot Residui') plt.subplot(2, 2, 3) plt.hist(residuals, bins=30, edgecolor='black', alpha=0.7) plt.xlabel('Residui (€)') plt.ylabel('Frequenza') plt.title('Distribuzione Residui') plt.grid(True, alpha=0.3) plt.subplot(2, 2, 4) plt.scatter(y_pred, y_test, alpha=0.6) plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2) plt.xlabel('Prezzo Predetto (€)') plt.ylabel('Prezzo Reale (€)') plt.title('Predetti vs Reali') plt.grid(True, alpha=0.3) plt.tight_layout() plt.show() """ # 7. PREDIZIONI SU NUOVI DATI print("\n\n7. 🔮 PREDIZIONI SU NUOVE CASE") print("-" * 40) # Crea dati per nuove case nuove_case = pd.DataFrame({ 'metratura': [150, 80, 200, 120], 'num_camere': [3, 2, 4, 3], 'eta_casa': [10, 30, 5, 20], 'distanza_centro': [2, 10, 5, 8] }) # Standardizza come abbiamo fatto per il training nuove_case_scaled = scaler.transform(nuove_case) # Predici prezzi prezzi_predetti = model.predict(nuove_case_scaled) print("🏠 PREZZI PREDETTI PER NUOVE CASE:") for i, (_, casa) in enumerate(nuove_case.iterrows()): print(f"\nCasa {i+1}:") print(f" Metratura: {casa['metratura']} m²") print(f" Camere: {casa['num_camere']}") print(f" Età: {casa['eta_casa']} anni") print(f" Distanza centro: {casa['distanza_centro']} km") print(f" 💰 Prezzo predetto: €{prezzi_predetti[i]:,.0f}") # 8. CROSS-VALIDATION PER VALUTAZIONE ROBUSTA print("\n\n8. 🔄 CROSS-VALIDATION") print("-" * 40) # 5-fold cross-validation cv_scores = cross_val_score( LinearRegression(), X_scaled, y, cv=5, scoring='r2', # Usiamo R² come metrica n_jobs=-1 ) print("🎯 R² SCORES CON 5-FOLD CROSS-VALIDATION:") for fold, score in enumerate(cv_scores, 1): print(f" Fold {fold}: {score:.3f}") print(f"\n📊 R² medio CV: {cv_scores.mean():.3f} (+/- {cv_scores.std()*2:.3f})") print(f"📈 R² sul test set: {r2:.3f}") # Valuta differenza diff = abs(cv_scores.mean() - r2) if diff < 0.05: print("✅ Performance consistenti tra CV e test set") else: print(f"⚠️ Differenza tra CV e test: {diff:.3f}") # 9. ANALISI DELL'INFLUENZA DELLE FEATURES print("\n\n9. 🎯 FEATURE IMPORTANCE") print("-" * 40) # Calcola importanza relativa delle features feature_importance = np.abs(model.coef_) feature_importance = 100.0 * (feature_importance / feature_importance.sum()) importance_df = pd.DataFrame({ 'Feature': features, 'Coefficiente': model.coef_, 'Importanza (%)': feature_importance }).sort_values('Importanza (%)', ascending=False) print("📊 IMPORTANZA RELATIVA DELLE FEATURES:") print(importance_df.to_string(index=False)) print("\n📈 SU GOOGLE COLAB, SCOMMENTA PER GRAFICO IMPORTANZA:") """ plt.figure(figsize=(10, 6)) bars = plt.barh(importance_df['Feature'], importance_df['Importanza (%)']) plt.xlabel('Importanza Relativa (%)') plt.title('Importanza delle Features nel Modello') plt.grid(True, alpha=0.3, axis='x') # Aggiungi valori sulle barre for bar in bars: width = bar.get_width() plt.text(width + 1, bar.get_y() + bar.get_height()/2, f'{width:.1f}%', ha='left', va='center') plt.tight_layout() plt.show() """ # 10. CONCLUSIONI E INSIGHTS print("\n\n10. 🎓 CONCLUSIONI E INSIGHTS") print("-" * 40) print("\n✅ COSA ABBIAMO IMPARATO:") print("1. Creazione e analisi dataset per regressione") print("2. Standardizzazione features per regressione lineare") print("3. Training modello e interpretazione coefficienti") print("4. Valutazione con metriche MSE, RMSE, MAE, R²") print("5. Analisi residui e verifica assunzioni") print("6. Cross-validation per valutazione robusta") print("7. Predizioni su nuovi dati") print("8. Analisi feature importance") print("\n📊 PERFORMANCE FINALI DEL MODELLO:") metrics_summary = pd.DataFrame({ 'Metrica': ['R² Score', 'RMSE', 'MAE', 'MSE'], 'Valore': [r2, f"€{rmse:,.0f}", f"€{mae:,.0f}", f"{mse:,.0f}"], 'Interpretazione': [ f"Spiega {r2*100:.1f}% della varianza", f"Errore medio €{rmse:,.0f} (±{rmse/prezzo_medio*100:.1f}%)", f"Errore assoluto medio €{mae:,.0f}", f"Errore quadratico medio" ] }) print(metrics_summary.to_string(index=False)) print("\n🎯 INSIGHTS PRATICI:") print(f"1. La metratura è la feature più importante ({importance_df.iloc[0]['Importanza (%)']:.1f}%)") print(f"2. Ogni camera in più vale circa €{abs(model.coef_[1]):,.0f}") print(f"3. Ogni anno di età riduce il valore di €{abs(model.coef_[2]):,.0f}") print(f"4. Ogni km dal centro riduce il valore di €{abs(model.coef_[3]):,.0f}") print("\n🚀 PROSSIMI PASSI:") print("1. Provare regressione polinomiale per relazioni non lineari") print("2. Aggiungere più features (quartiere, servizi, etc.)") print("3. Provare altri algoritmi (Random Forest, Gradient Boosting)") print("4. Ottimizzare con regularizzazione (Ridge, Lasso)") print("\n🎉 COMPLIMENTI! HAI COMPLETATO LA REGRESSIONE LINEARE!")
β₁
Coefficiente Metratura
≈ 50,000 €/m²
β₂
Coefficiente Camere
≈ 20,000 €/camera
β₃
Coefficiente Età
≈ -2,000 €/anno
β₀
Intercetta
≈ 100,000 €

💡 Interpretazione dei Coefficienti

β₁ (Metratura): Per ogni metro quadro in più, il prezzo aumenta di β₁ €

β₂ (Camere): Ogni camera aggiuntiva vale β₂ €

β₃ (Età): Per ogni anno in più, il valore diminuisce di |β₃| €

β₀ (Intercetta): Prezzo base quando tutte le features sono zero

📈 Regressione Lineare Semplice (1 Variabile)

Partiamo dal caso base con una sola feature per capire i concetti fondamentali.

🚫 COPIA BLOCCATA
# REGRESSIONE LINEARE SEMPLICE - ANNI ESPERIENZA vs STIPENDIO import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score, mean_squared_error print("👔 REGRESSIONE LINEARE SEMPLICE: Esperienza vs Stipendio") print("=" * 70) # Creazione dati sintetici np.random.seed(42) n_samples = 50 # Anni di esperienza (feature X) anni_esperienza = np.random.uniform(0, 20, n_samples) # Stipendio base: €30,000 + €5,000 per anno + rumore stipendio_base = 30000 incremento_per_anno = 5000 rumore = np.random.normal(0, 8000, n_samples) # Rumore realistico stipendio = stipendio_base + (incremento_per_anno * anni_esperienza) + rumore # Crea DataFrame df_stipendi = pd.DataFrame({ 'anni_esperienza': anni_esperienza, 'stipendio': stipendio }) print("\n📊 DATASET STIPENDI (prime 10 righe):") print(df_stipendi.head(10).round(0)) print(f"\n📈 Statistiche:") print(f"Esperienza media: {df_stipendi['anni_esperienza'].mean():.1f} anni") print(f"Stipendio medio: €{df_stipendi['stipendio'].mean():,.0f}") # 1. VISUALIZZAZIONE DATI print("\n\n1. 📊 VISUALIZZAZIONE RELAZIONE LINEARE") print("-" * 40) print("📈 SU GOOGLE COLAB, SCOMMENTA PER IL GRAFICO:") """ plt.figure(figsize=(10, 6)) plt.scatter(df_stipendi['anni_esperienza'], df_stipendi['stipendio'], alpha=0.6, s=80) plt.title('Relazione: Anni Esperienza vs Stipendio') plt.xlabel('Anni di Esperienza') plt.ylabel('Stipendio (€)') plt.grid(True, alpha=0.3) plt.show() """ # 2. PREPARAZIONE DATI print("\n\n2. 🛠️ PREPARAZIONE DATI PER REGRESSIONE") print("-" * 40) # Regressione semplice: X deve essere matrice 2D (n_samples, n_features) X = df_stipendi[['anni_esperienza']] # Doppie parentesi per matrice 2D y = df_stipendi['stipendio'] print(f"Shape X: {X.shape}") # (50, 1) print(f"Shape y: {y.shape}") # (50,) # 3. TRAINING MODELLO print("\n\n3. 🤖 TRAINING REGRESSIONE LINEARE SEMPLICE") print("-" * 40) # Crea e addestra modello model_semplice = LinearRegression() model_semplice.fit(X, y) print("✅ Modello addestrato!") print(f"\n🎯 PARAMETRI DEL MODELLO:") print(f"Coefficiente angolare (β₁): {model_semplice.coef_[0]:,.0f} €/anno") print(f"Intercetta (β₀): {model_semplice.intercept_:,.0f} €") # 4. PREDIZIONI print("\n\n4. 🔮 PREDIZIONI E RETTA DI REGRESSIONE") print("-" * 40) # Crea range di valori per la retta x_range = np.linspace(0, 20, 100).reshape(-1, 1) y_pred_range = model_semplice.predict(x_range) # Predici per alcuni valori specifici anni_test = np.array([[0], [5], [10], [15], [20]]).reshape(-1, 1) stipendi_pred = model_semplice.predict(anni_test) print("\n📊 PREDIZIONI PER VARI ANNI DI ESPERIENZA:") for anni, stipendio_pred in zip(anni_test.flatten(), stipendi_pred): print(f" {anni:2.0f} anni: €{stipendio_pred:,.0f}") print("\n📈 SU GOOGLE COLAB, SCOMMENTA PER VISUALIZZARE LA RETTA:") """ plt.figure(figsize=(10, 6)) # Punti originali plt.scatter(X, y, alpha=0.6, s=80, label='Dati reali') # Retta di regressione plt.plot(x_range, y_pred_range, color='red', linewidth=3, label=f'Retta regressione: y = {model_semplice.intercept_:.0f} + {model_semplice.coef_[0]:.0f}x') plt.title('Regressione Lineare Semplice: Esperienza vs Stipendio') plt.xlabel('Anni di Esperienza') plt.ylabel('Stipendio (€)') plt.legend() plt.grid(True, alpha=0.3) plt.show() """ # 5. VALUTAZIONE MODELLO print("\n\n5. 📊 VALUTAZIONE PERFORMANCE") print("-" * 40) # Predizioni su tutto il dataset y_pred = model_semplice.predict(X) # Calcola metriche r2 = r2_score(y, y_pred) mse = mean_squared_error(y, y_pred) rmse = np.sqrt(mse) print(f"🎯 R² Score: {r2:.3f}") print(f"🎯 Mean Squared Error (MSE): {mse:,.0f}") print(f"🎯 Root Mean Squared Error (RMSE): €{rmse:,.0f}") print(f"🎯 Errore percentuale medio: {(rmse/y.mean()*100):.1f}%") # 6. INTERPRETAZIONE PRATICA print("\n\n6. 💼 INTERPRETAZIONE PRATICA PER LE RISORSE UMANE") print("-" * 40) print("\n🎯 INSIGHTS PER HR:") print(f"1. Stipendio base (0 anni esperienza): €{model_semplice.intercept_:,.0f}") print(f"2. Incremento annuo atteso: €{model_semplice.coef_[0]:,.0f}/anno") print(f"3. Stipendio atteso dopo 5 anni: €{model_semplice.predict([[5]])[0]:,.0f}") print(f"4. Stipendio atteso dopo 10 anni: €{model_semplice.predict([[10]])[0]:,.0f}") # Calcola intervallo di confidenza semplice (approssimato) std_error = rmse print(f"\n📊 INTERVALLO DI CONFIDENZA (approssimato):") print(f"Per una predizione, il vero stipendio è probabilmente tra:") print(f" Predetto ± €{std_error:,.0f} (circa ±{(std_error/model_semplice.predict([[10]])[0]*100):.1f}%)") # 7. ANALISI DEI CASI PARTICOLARI print("\n\n7. 🔍 ANALISI DEI DATI ATIPICI (OUTLIERS)") print("-" * 40) # Calcola residui residui = y - y_pred # Identifica outliers (residui > 2*std) residui_std = residui.std() outliers_idx = np.abs(residui) > 2 * residui_std print(f"📈 Statistiche residui:") print(f"Media residui: €{residui.mean():,.0f}") print(f"Deviazione standard residui: €{residui_std:,.0f}") print(f"\n🎯 Outliers identificati: {outliers_idx.sum()} su {len(y)}") if outliers_idx.any(): print("\n📊 DATI ATIPICI TROVATI:") for idx in np.where(outliers_idx)[0]: exp = X.iloc[idx, 0] stip_reale = y.iloc[idx] stip_pred = y_pred[idx] residuo = residui.iloc[idx] print(f" Esperienza: {exp:.1f} anni, Reale: €{stip_reale:,.0f}, " f"Predetto: €{stip_pred:,.0f}, Differenza: €{residuo:,.0f}") # 8. SIMULAZIONE CON NUOVI DATI print("\n\n8. 🔮 SIMULAZIONE: NUOVI CANDIDATI") print("-" * 40) # Simula nuovi candidati nuovi_candidati = pd.DataFrame({ 'anni_esperienza': [2.5, 7, 12, 18, 0.5] }) # Predici stipendi stipendi_nuovi = model_semplice.predict(nuovi_candidati[['anni_esperienza']]) print("💰 STIPENDI RACCOMANDATI PER NUOVI CANDIDATI:") for i, (_, cand) in enumerate(nuovi_candidati.iterrows()): anni = cand['anni_esperienza'] stipendio = stipendi_nuovi[i] print(f"\nCandidato {i+1}:") print(f" Anni esperienza: {anni}") print(f" 💰 Stipendio raccomandato: €{stipendio:,.0f}") print(f" Range probabile: €{stipendio - std_error:,.0f} - €{stipendio + std_error:,.0f}") print("\n🎯 CONSIGLI PER NEGOZIAZIONE STIPENDI:") print("1. Usa questa retta come benchmark di mercato") print("2. Considera ±€{0:,.0f} come range di negoziazione".format(std_error)) print("3. Per esperienze atipiche, valuta skills specifiche") print("4. Ricorda: la regressione mostra trend, non destini!") print("\n📊 RIEPILOGO MODELLO:") print(f"Equazione: stipendio = {model_semplice.intercept_:,.0f} + {model_semplice.coef_[0]:,.0f} * anni_esperienza") print(f"Bontà del fit: R² = {r2:.3f} ({r2*100:.1f}% varianza spiegata)") print(f"Errore tipico: ±€{rmse:,.0f} per predizione") print("\n🎉 REGRESSIONE LINEARE SEMPLICE MASTERED!")
Coefficiente Determinazione
0.85 - 0.95 tipico
RMSE
Root Mean Square Error
±5-10% del target
β₁
Coefficiente Angolare
€/unit feature
n
Campioni Minimi
> 30 consigliato

⚠️ Limitazioni Regressione Lineare Semplice

1. Relazioni non lineari: Non cattura curve, solo rette

2. Multicolinearità: Con più features, problemi se correlate

3. Outliers sensibili: Un outlier può spostare molto la retta

4. Assunzioni forti: Linearità, normalità errori, omoschedasticità

💪 Esercizi di Regressione Lineare

Esercizio 1: Previsione Vendite FACILE

Hai dati storici di vendite mensili e budget marketing:

🚫 COPIA BLOCCATA
import numpy as np np.random.seed(42) n_mesi = 36 # Budget marketing (in migliaia di €) budget = np.random.uniform(10, 100, n_mesi) # Vendite (in migliaia di €): base 50 + 2*budget + rumore vendite = 50 + 2 * budget + np.random.normal(0, 20, n_mesi)

Analisi richiesta:

  1. Crea scatter plot vendite vs budget
  2. Addestra regressione lineare semplice
  3. Interpreta coefficiente: ROI marketing
  4. Predici vendite per budget di 80k€
  5. Calcola R² e interpreta

Esercizio 2: Predizione Prezzi Auto MEDIO

Dataset auto usate con: chilometraggio, anno, cilindrata, prezzo.

Obiettivi:

  1. Analisi correlazioni tra tutte le features
  2. Regressione lineare multipla con tutte le features
  3. Analisi residui e verifica assunzioni
  4. Identifica feature più importante
  5. Cross-validation per valutazione robusta

Esercizio 3: Salary Survey Analysis DIFFICILE

Analisi stipendi reali con multiple features:

  1. Features: Esperienza, Educazione (1-5), Ruolo (categorico), Regione
  2. Target: Stipendio annuo

Tasks avanzate:

  1. Encoding variabili categoriche (One-Hot Encoding)
  2. Feature engineering: crea "esperienza_quadrato"
  3. Regressione con regularizzazione (Ridge/Lasso)
  4. Confronta performance modelli semplice vs multipla
  5. Costruisci intervalli di confidenza per predizioni

🚀 Verso la Regressione Multipla

📈 Regressione Lineare Semplice vs Multipla

Aspect Semplice Multipla
Features 1 2+
Equazione y = β₀ + β₁x y = β₀ + β₁x₁ + ... + βₙxₙ
Visualizzazione 2D (retta) nD (iperpiano)
Complessità Bassa Media-Alta

🎯 Cosa imparerai nel prossimo modulo:

  1. Regressione Multipla: Più features, più potere predittivo
  2. Multicollinearità: Quando le features sono correlate tra loro
  3. Feature Selection: Scegliere le features più importanti
  4. Regularizzazione: Ridge e Lasso per prevenire overfitting
  5. Polynomial Features: Catturare relazioni non lineari
Vai alla Regressione Multipla →