CLASSE QUARTA • DATA SCIENCE AVANZATA

Data Analysis Avanzata

Merge, Pivot, Time Series e Tecniche Professionali

Livello up! Ora che padroneggi i DataFrame, esploriamo le tecniche avanzate usate dai data scientist professionisti per analisi complesse.

Data Cleaning
Merge & Join
Pivot Tables
Time Series
Advanced Analysis

🧹 Data Cleaning Avanzato

Nella realtà, i dati sono sporchi. Ecco come pulirli come un professionista.

🚫 COPIA BLOCCATA
import pandas as pd import numpy as np # Dataset di esempio "sporco" dati_sporchi = { 'ID': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'Nome': ['Mario', 'Luigi', None, 'Anna', '', 'Giovanni', 'Maria', np.nan, 'Luca', 'Sofia'], 'Età': [25, 'ventotto', 30, '??', 22, 35, 'quaranta', 28, 31, ''], 'Stipendio': ['30.000', '45,000', 'N/A', '38000', '', '42000', '50000', '35000', 'abc', '48000'], 'Dipartimento': ['IT', 'Vendite', 'IT', None, 'HR', 'Vendite', 'Marketing', 'IT', 'HR', 'Vendite'], 'Data_Assunzione': ['2020-01-15', '2019-03-20', '2021-05-10', '2018-11-05', '2022-02-28', '2017-07-12', '2020-09-30', '2023-01-01', '2019-08-15', '2021-12-10'] } df = pd.DataFrame(dati_sporchi) print("📊 DATASET SPORCO ORIGINALE:") print(df) print("\n" + "="*60) # 1. ANALISI INIZIALE print("\n🔍 ANALISI PROBLEMI:") print(f"Dimensioni: {df.shape}") print(f"Valori nulli per colonna:") print(df.isnull().sum()) print(f"\nValori vuoti/stringhe:") for col in df.columns: vuoti = df[col].apply(lambda x: isinstance(x, str) and x.strip() == '').sum() if vuoti > 0: print(f"{col}: {vuoti} valori vuoti") # 2. PULIZIA NOMI print("\n🧼 1. PULIZIA COLONNA 'NOME':") # Sostituisce NaN e stringhe vuote con 'Sconosciuto' df['Nome'] = df['Nome'].replace(['', np.nan, None], 'Sconosciuto') # Rimuove spazi extra df['Nome'] = df['Nome'].astype(str).str.strip() # Capitalizza correttamente df['Nome'] = df['Nome'].str.title() # 3. PULIZIA ETÀ print("\n🎂 2. PULIZIA COLONNA 'ETÀ':") # Funzione per convertire età def pulisci_eta(val): if pd.isna(val) or val == '': return np.nan if isinstance(val, (int, float)): return float(val) if isinstance(val, str): # Rimuove caratteri non numerici import re numeri = re.findall(r'\d+', val) if numeri: return float(numeri[0]) return np.nan df['Età'] = df['Età'].apply(pulisci_eta) # Riempie valori mancanti con la mediana eta_mediana = df['Età'].median() df['Età'] = df['Età'].fillna(eta_mediana) # 4. PULIZIA STIPENDIO print("\n💰 3. PULIZIA COLONNA 'STIPENDIO':") def pulisci_stipendio(val): if pd.isna(val) or val == '': return np.nan if isinstance(val, (int, float)): return float(val) if isinstance(val, str): # Rimuove punti, virgole, spazi val_pulito = str(val).replace('.', '').replace(',', '').replace(' ', '') # Rimuove testo non numerico try: return float(val_pulito) except: return np.nan return np.nan df['Stipendio'] = df['Stipendio'].apply(pulisci_stipendio) # Riempie con la media del dipartimento media_per_dipartimento = df.groupby('Dipartimento')['Stipendio'].transform('mean') df['Stipendio'] = df['Stipendio'].fillna(media_per_dipartimento) # 5. PULIZIA DIPARTIMENTO print("\n🏢 4. PULIZIA COLONNA 'DIPARTIMENTO':") df['Dipartimento'] = df['Dipartimento'].fillna('Non Specificato') df['Dipartimento'] = df['Dipartimento'].astype(str).str.strip().str.title() # 6. CONVERSIONE DATE print("\n📅 5. CONVERSIONE COLONNA 'DATA_ASSUNZIONE':") df['Data_Assunzione'] = pd.to_datetime(df['Data_Assunzione'], errors='coerce') # Per date mancanti, metti una data ragionevole df['Data_Assunzione'] = df['Data_Assunzione'].fillna(pd.Timestamp('2022-01-01')) # 7. RIMOZIONE DUPLICATI E OUTLIERS print("\n🎯 6. GESTIONE DUPLICATI E OUTLIERS:") # Rimuove duplicati basati su ID df = df.drop_duplicates(subset=['ID']) # Identifica outliers nello stipendio (z-score > 3) from scipy import stats z_scores = np.abs(stats.zscore(df['Stipendio'].dropna())) outliers = z_scores > 3 print(f"Outliers nello stipendio trovati: {outliers.sum()}") # 8. DATASET PULITO print("\n✨ DATASET FINALE PULITO:") print(df) print("\n📊 STATISTICHE FINALI:") print(f"Valori nulli rimasti: {df.isnull().sum().sum()}") print(f"Range età: {df['Età'].min():.0f} - {df['Età'].max():.0f}") print(f"Range stipendio: {df['Stipendio'].min():,.0f} - {df['Stipendio'].max():,.0f}") print(f"Date: da {df['Data_Assunzione'].min().date()} a {df['Data_Assunzione'].max().date()}") print("\n✅ DATA CLEANING COMPLETATO!")

🎯 Tecniche Professionali di Data Cleaning:

Problema Soluzione Codice
Valori mancanti Imputazione con media/mediana .fillna(), .interpolate()
Stringhe inconsistenti Normalizzazione con .str .str.strip(), .str.title()
Tipi di dati errati Conversioni mirate pd.to_numeric(), pd.to_datetime()
Duplicati Identificazione e rimozione .duplicated(), .drop_duplicates()
Outliers Rilevamento con z-score stats.zscore()

🔗 Merge & Join di DataFrame

Unisci dati da diverse fonti come un database SQL.

ID
Nome
1 Mario
2 Luigi
3 Anna
+
ID
Dipartimento
1 IT
2 Vendite
4 Marketing
ID
Nome
Dipartimento
1 Mario IT
2 Luigi Vendite
3 Anna NaN
🚫 COPIA BLOCCATA
import pandas as pd # DATASET 1: Dipendenti dipendenti = pd.DataFrame({ 'Employee_ID': [101, 102, 103, 104, 105], 'Nome': ['Mario Rossi', 'Luigi Verdi', 'Anna Bianchi', 'Giovanni Neri', 'Sofia Russo'], 'Dipartimento_ID': [10, 20, 10, 30, 20], 'Stipendio_Base': [35000, 42000, 38000, 45000, 39000] }) # DATASET 2: Dipartimenti dipartimenti = pd.DataFrame({ 'Dept_ID': [10, 20, 30, 40], 'Nome_Dipartimento': ['IT', 'Vendite', 'Marketing', 'HR'], 'Manager': ['Carlo Esposito', 'Laura Romano', 'Paolo Conti', 'Elena Marini'], 'Budget': [500000, 750000, 400000, 300000] }) # DATASET 3: Performance performance = pd.DataFrame({ 'Employee_ID': [101, 102, 104, 105, 106], 'Voto_Performance': [85, 92, 78, 88, 95], 'Bonus': [3500, 5000, 2500, 4000, 4500] }) print("📊 DATASET ORIGINALI:") print("\n1. DIPENDENTI:") print(dipendenti) print("\n2. DIPARTIMENTI:") print(dipartimenti) print("\n3. PERFORMANCE:") print(performance) print("\n" + "="*60) # 1. INNER JOIN (intersezione) print("\n🔗 1. INNER JOIN (solo corrispondenze):") inner_merge = pd.merge(dipendenti, performance, on='Employee_ID', how='inner') print("Risultato Inner Join:") print(inner_merge) print(f"\nRighe risultanti: {len(inner_merge)}") # 2. LEFT JOIN (tutti i dipendenti) print("\n⬅️ 2. LEFT JOIN (tutti i dipendenti):") left_merge = pd.merge(dipendenti, performance, on='Employee_ID', how='left') print("Risultato Left Join:") print(left_merge) print(f"\nRighe risultanti: {len(left_merge)}") # 3. RIGHT JOIN (tutte le performance) print("\n➡️ 3. RIGHT JOIN (tutte le performance):") right_merge = pd.merge(dipendenti, performance, on='Employee_ID', how='right') print("Risultato Right Join:") print(right_merge) print(f"\nRighe risultanti: {len(right_merge)}") # 4. FULL OUTER JOIN (tutto) print("\n🔄 4. FULL OUTER JOIN (tutti i dati):") full_merge = pd.merge(dipendenti, performance, on='Employee_ID', how='outer') print("Risultato Full Outer Join:") print(full_merge) print(f"\nRighe risultanti: {len(full_merge)}") # 5. MERGE CON PIÙ CHIAVI print("\n🔑 5. MERGE CON PIÙ COLONNE:") # Aggiungiamo dipartimento ai dipendenti con performance dipendenti_con_dept = pd.merge(dipendenti, dipartimenti, left_on='Dipartimento_ID', right_on='Dept_ID', how='left') completo = pd.merge(dipendenti_con_dept, performance, on='Employee_ID', how='left') print("Dataset completo (3 tabelle unite):") print(completo[['Employee_ID', 'Nome', 'Nome_Dipartimento', 'Stipendio_Base', 'Voto_Performance', 'Bonus']]) # 6. MERGE CON SUFFISSI print("\n🏷️ 6. MERGE CON COLONNE OMONIME:") # Creiamo due dataset con colonne omonime stipendi_2023 = pd.DataFrame({ 'Employee_ID': [101, 102, 103], 'Stipendio': [35000, 42000, 38000], 'Anno': [2023, 2023, 2023] }) stipendi_2024 = pd.DataFrame({ 'Employee_ID': [101, 102, 104], 'Stipendio': [37000, 44000, 47000], 'Anno': [2024, 2024, 2024] }) # Merge con suffissi stipendi_comparison = pd.merge(stipendi_2023, stipendi_2024, on='Employee_ID', how='outer', suffixes=('_2023', '_2024')) print("Confronto stipendi 2023-2024:") print(stipendi_comparison) # 7. JOIN CON INDICE print("\n🎯 7. JOIN USANDO INDICI:") # Imposta Employee_ID come indice dip_indice = dipendenti.set_index('Employee_ID') perf_indice = performance.set_index('Employee_ID') # Join su indice join_indice = dip_indice.join(perf_indice, how='left') print("Join usando indici:") print(join_indice) # 8. CONCATENAZIONE print("\n📎 8. CONCATENAZIONE VERTICALE (append):") dipendenti_nuovi = pd.DataFrame({ 'Employee_ID': [106, 107], 'Nome': ['Marco Ferrari', 'Giulia Santoro'], 'Dipartimento_ID': [10, 40], 'Stipendio_Base': [41000, 36000] }) tutti_dipendenti = pd.concat([dipendenti, dipendenti_nuovi], ignore_index=True) print("Tutti i dipendenti (concatenati):") print(tutti_dipendenti)

📖 Tipi di Join in SQL vs Pandas:

Tipo Join SQL Pandas Descrizione
INNER JOIN INNER JOIN how='inner' Solo righe con corrispondenza
LEFT JOIN LEFT OUTER JOIN how='left' Tutte righe sinistra + corrispondenze destra
RIGHT JOIN RIGHT OUTER JOIN how='right' Tutte righe destra + corrispondenze sinistra
FULL JOIN FULL OUTER JOIN how='outer' Tutte le righe da entrambe
CROSS JOIN CROSS JOIN .merge(how='cross') Prodotto cartesiano

📊 Pivot Tables e Analisi Multidimensionale

Trasforma i tuoi dati in insights potenti con le tabelle pivot.

🚫 COPIA BLOCCATA
import pandas as pd import numpy as np # Dataset di vendite np.random.seed(42) date_range = pd.date_range('2024-01-01', '2024-03-31', freq='D') mesi = 3 giorni_per_mese = 30 dati_vendite = [] prodotti = ['Laptop', 'Tablet', 'Smartphone', 'Monitor', 'Accessori'] categorie = ['Elettronica', 'Elettronica', 'Elettronica', 'Periferiche', 'Accessori'] regioni = ['Nord', 'Centro', 'Sud', 'Isole'] for i in range(len(date_range)): prodotto = np.random.choice(prodotti) idx_prodotto = prodotti.index(prodotto) categoria = categorie[idx_prodotto] regione = np.random.choice(regioni) prezzo_unitario = np.random.choice([800, 400, 700, 300, 50]) quantita = np.random.randint(1, 10) vendite_totali = prezzo_unitario * quantita dati_vendite.append({ 'Data': date_range[i], 'Prodotto': prodotto, 'Categoria': categoria, 'Regione': regione, 'Prezzo_Unitario': prezzo_unitario, 'Quantità': quantita, 'Vendite_Totali': vendite_totali }) df_vendite = pd.DataFrame(dati_vendite) df_vendite['Mese'] = df_vendite['Data'].dt.month_name() df_vendite['Giorno_Settimana'] = df_vendite['Data'].dt.day_name() print("📈 DATASET VENDITE (prime 10 righe):") print(df_vendite.head(10)) print(f"\n📊 Dimensioni: {df_vendite.shape}") print(f"Periodo: {df_vendite['Data'].min().date()} - {df_vendite['Data'].max().date()}") print("\n" + "="*70) # 1. PIVOT TABLE BASE print("\n🎯 1. PIVOT TABLE BASE - Vendite per Prodotto e Regione:") pivot_base = pd.pivot_table(df_vendite, values='Vendite_Totali', index='Prodotto', columns='Regione', aggfunc='sum', margins=True, # Aggiunge totali margins_name='TOTALE') print("Vendite Totali per Prodotto e Regione:") print(pivot_base) print(f"\nVendite totali complessive: €{pivot_base.loc['TOTALE', 'TOTALE']:,.0f}") # 2. PIVOT TABLE MULTI-LIVELLO print("\n🏗️ 2. PIVOT TABLE MULTI-LIVELLO - Categoria e Prodotto:") pivot_multi = pd.pivot_table(df_vendite, values=['Vendite_Totali', 'Quantità'], index=['Categoria', 'Prodotto'], columns='Mese', aggfunc={'Vendite_Totali': 'sum', 'Quantità': 'sum'}, fill_value=0) print("Vendite e Quantità per Categoria/Prodotto/Mese:") print(pivot_multi) # 3. PIVOT CON PIÙ FUNZIONI DI AGGR. print("\n📊 3. PIVOT CON STATISTICHE MULTIPLE:") pivot_stats = pd.pivot_table(df_vendite, values='Vendite_Totali', index='Regione', columns='Mese', aggfunc=['sum', 'mean', 'count', 'std'], fill_value=0) print("Statistiche Vendite per Regione e Mese:") print(pivot_stats) # 4. PIVOT TABLE CON DATE print("\n📅 4. PIVOT CON ANALISI TEMPORALE:") # Aggiungi colonna settimana df_vendite['Settimana'] = df_vendite['Data'].dt.isocalendar().week pivot_tempo = pd.pivot_table(df_vendite, values='Vendite_Totali', index='Settimana', columns='Prodotto', aggfunc='sum', fill_value=0) print("Vendite per Settimana e Prodotto:") print(pivot_tempo.head(10)) # 5. CROSS TAB (per frequenze) print("\n🔢 5. CROSS TABULATION - Conteggio Transazioni:") cross_tab = pd.crosstab(index=[df_vendite['Categoria'], df_vendite['Prodotto']], columns=[df_vendite['Regione'], df_vendite['Mese']], margins=True) print("Conteggio Transazioni per Categoria/Prodotto/Regione/Mese:") print(cross_tab) # 6. PIVOT CON CALCOLI DERIVATI print("\n🎨 6. PIVOT CON CALCOLI PERSONALIZZATI:") # Prima crea un pivot normale pivot_qta = pd.pivot_table(df_vendite, values='Quantità', index='Prodotto', columns='Mese', aggfunc='sum', fill_value=0) # Calcola percentuali pivot_percent = pivot_qta.div(pivot_qta.sum(axis=1), axis=0) * 100 print("Percentuale Quantità per Prodotto/Mese:") print(pivot_percent.round(1)) # 7. PIVOT STACKED/UNSTACKED print("\n♻️ 7. OPERAZIONI STACK/UNSTACK:") pivot_flat = pd.pivot_table(df_vendite, values='Vendite_Totali', index=['Regione', 'Mese'], columns='Prodotto', aggfunc='sum') print("Pivot Flat (primi 5 righe):") print(pivot_flat.head()) print("\n📦 Pivot Stacked (multi-indice):") stacked = pivot_flat.stack() print(stacked.head(15)) print("\n📤 Pivot Unstacked:") unstacked = stacked.unstack() print(unstacked.head()) # 8. ANALISI CON GROUPBY (alternativa a pivot) print("\n👥 8. GROUPBY AVANZATO - Analisi Comparable:") analisi_completa = df_vendite.groupby(['Categoria', 'Prodotto', 'Mese']).agg({ 'Vendite_Totali': ['sum', 'mean', 'count', 'std'], 'Quantità': ['sum', 'mean', 'max'], 'Prezzo_Unitario': 'mean' }).round(2) print("Analisi Completa GroupBy:") print(analisi_completa) # 9. VISUALIZZAZIONE PIVOT (per Google Colab) print("\n📈 9. VISUALIZZAZIONE DATI (per Google Colab):") # Nota: Su Google Colab, scommenta per vedere i grafici """ import matplotlib.pyplot as plt # Prepara dati per grafico pivot_grafico = pd.pivot_table(df_vendite, values='Vendite_Totali', index='Mese', columns='Regione', aggfunc='sum') # Crea grafico plt.figure(figsize=(10, 6)) pivot_grafico.plot(kind='bar', stacked=True) plt.title('Vendite Totali per Mese e Regione') plt.xlabel('Mese') plt.ylabel('Vendite Totali (€)') plt.legend(title='Regione') plt.tight_layout() plt.show() """ print("\n✅ ANALISI PIVOT COMPLETATA!") print("\n📊 RIEPILOGO INSIGHTS:") print(f"1. Prodotto più venduto: {df_vendite.groupby('Prodotto')['Vendite_Totali'].sum().idxmax()}") print(f"2. Regione con maggior fatturato: {df_vendite.groupby('Regione')['Vendite_Totali'].sum().idxmax()}") print(f"3. Mese migliore: {df_vendite.groupby('Mese')['Vendite_Totali'].sum().idxmax()}") print(f"4. Media vendite giornaliera: €{df_vendite['Vendite_Totali'].mean():,.0f}")

💡 Quando usare Pivot Table vs GroupBy:

Pivot Table: Per report tabellari, dashboard, visualizzazioni incrociate

GroupBy: Per calcoli complessi, aggregazioni multiple, pipeline di dati

Crosstab: Per tabelle di frequenza, analisi di conteggio

⏱️ Time Series Analysis

Analizza dati temporali con le potenti funzioni di Pandas.

🚫 COPIA BLOCCATA
import pandas as pd import numpy as np # 1. CREAZIONE SERIE TEMPORALE print("⏱️ 1. CREAZIONE SERIE TEMPORALE") print("="*50) # Crea range di date date_range = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D') # Daily frequency print(f"Range date creato: {len(date_range)} giorni") print(f"Da: {date_range[0]} a {date_range[-1]}") # Crea dati casuali con trend stagionale np.random.seed(42) n = len(date_range) trend = np.linspace(100, 150, n) # Trend crescente seasonality = 20 * np.sin(2 * np.pi * np.arange(n) / 30) # Stagionalità mensile noise = np.random.normal(0, 5, n) # Rumore sales = trend + seasonality + noise # Crea DataFrame df_ts = pd.DataFrame({ 'Date': date_range, 'Sales': sales, 'Temperature': np.random.uniform(10, 30, n), # Dati meteo fittizi 'Marketing_Spend': np.random.exponential(100, n) }) # Imposta data come indice df_ts.set_index('Date', inplace=True) print("\n📊 SERIE TEMPORALE CREATA (prime 10 righe):") print(df_ts.head(10)) print(f"\n📈 Statistiche vendite: Min={df_ts['Sales'].min():.1f}, " f"Max={df_ts['Sales'].max():.1f}, Mean={df_ts['Sales'].mean():.1f}") # 2. RESAMPLING (cambio frequenza) print("\n\n🔄 2. RESAMPLING - Cambio Frequenza") print("="*50) # Giornaliero -> Settimanale weekly_sales = df_ts['Sales'].resample('W').agg(['mean', 'sum', 'std']) print("📅 VENDITE SETTIMANALI (media, somma, dev std):") print(weekly_sales.head()) # Giornaliero -> Mensile monthly_stats = df_ts.resample('M').agg({ 'Sales': ['sum', 'mean', 'max', 'min'], 'Temperature': 'mean', 'Marketing_Spend': 'sum' }) print("\n📆 STATISTICHE MENSILI:") print(monthly_stats) # 3. ROLLING STATISTICS print("\n\n📈 3. ROLLING STATISTICS - Media Mobile") print("="*50) # Media mobile 7 giorni (settimana) df_ts['Sales_7D_Avg'] = df_ts['Sales'].rolling(window=7).mean() df_ts['Sales_30D_Avg'] = df_ts['Sales'].rolling(window=30).mean() df_ts['Sales_Std_7D'] = df_ts['Sales'].rolling(window=7).std() print("📊 DATI CON MEDIE MOBILI (prime 15 righe):") print(df_ts[['Sales', 'Sales_7D_Avg', 'Sales_30D_Avg']].head(15)) # 4. SHIFT E DIFFERENZE print("\n\n📊 4. SHIFT E DIFFERENZE - Analisi Variazioni") print("="*50) # Differenza giorno precedente df_ts['Sales_Daily_Change'] = df_ts['Sales'].diff() df_ts['Sales_Pct_Change'] = df_ts['Sales'].pct_change() * 100 # Differenza settimana precedente df_ts['Sales_Weekly_Change'] = df_ts['Sales'].diff(7) print("📈 VARIAZIONI GIORNALIERE (prime 10 righe):") print(df_ts[['Sales', 'Sales_Daily_Change', 'Sales_Pct_Change']].head(10)) print(f"\n📊 Media variazione giornaliera: {df_ts['Sales_Daily_Change'].mean():.2f}") print(f"Max aumento giornaliero: {df_ts['Sales_Daily_Change'].max():.2f}") print(f"Max decremento giornaliero: {df_ts['Sales_Daily_Change'].min():.2f}") # 5. DECOMPOSIZIONE STAGIONALE print("\n\n🎯 5. DECOMPOSIZIONE STAGIONALE") print("="*50) from statsmodels.tsa.seasonal import seasonal_decompose # Prepara dati mensili per decomposizione monthly_sales = df_ts['Sales'].resample('M').sum() # Decomposizione (additiva) decomposition = seasonal_decompose(monthly_sales, model='additive', period=12) print("📊 COMPONENTI DECOMPOSIZIONE:") print(f"Trend (primi 5): {decomposition.trend.head(5).values}") print(f"Stagionalità (primi 5): {decomposition.seasonal.head(5).values}") print(f"Residui (primi 5): {decomposition.resid.head(5).values}") # 6. ANALISI CORRELAZIONI TEMPORALI print("\n\n🔗 6. CORRELAZIONI TEMPORALI") print("="*50) # Lag analysis: vendite vs marketing spend (shiftato) lags = range(1, 8) # Analizza lag da 1 a 7 giorni correlations = [] for lag in lags: corr = df_ts['Sales'].corr(df_ts['Marketing_Spend'].shift(lag)) correlations.append(corr) print(f"Lag {lag} giorni: Correlazione = {corr:.3f}") # Trova lag ottimale optimal_lag = lags[np.argmax(correlations)] print(f"\n🎯 Lag ottimale: {optimal_lag} giorni (correlazione massima)") # 7. TIME-BASED INDEXING print("\n\n🎯 7. SELEZIONI TEMPORALI") print("="*50) # Selezione per periodo specifico january_sales = df_ts.loc['2024-01'] print("📅 VENDITE DI GENNAIO 2024:") print(f"Media: {january_sales['Sales'].mean():.1f}") print(f"Totale: {january_sales['Sales'].sum():.1f}") # Selezione per trimestre q1_sales = df_ts.loc['2024-Q1'] print(f"\n📊 VENDITE Q1 2024: Totale = {q1_sales['Sales'].sum():.1f}") # Selezione per weekend vs weekday df_ts['Is_Weekend'] = df_ts.index.dayofweek >= 5 # 5=Sabato, 6=Domenica weekend_stats = df_ts.groupby('Is_Weekend')['Sales'].agg(['mean', 'sum', 'count']) print("\n📆 VENDITE WEEKEND vs WEEKDAY:") print(weekend_stats) # 8. FORECASTING SEMPLICE print("\n\n🔮 8. FORECASTING BASE") print("="*50) # Media mobile per forecasting last_30_days_avg = df_ts['Sales'].iloc[-30:].mean() print(f"📈 MEDIA ULTIMI 30 GIORNI: {last_30_days_avg:.1f}") # Forecast semplice: assumi crescita del 5% sul mese precedente last_month = df_ts.loc['2024-12']['Sales'].sum() forecast_next_month = last_month * 1.05 print(f"🎯 FORECAST GENNAIO 2025: {forecast_next_month:.1f} (+5%)") # 9. ESPORTAZIONE RISULTATI print("\n\n💾 9. ESPORTAZIONE RISULTATI") print("="*50) # Prepara report mensile monthly_report = df_ts.resample('M').agg({ 'Sales': ['sum', 'mean', 'std', 'min', 'max'], 'Temperature': 'mean', 'Marketing_Spend': 'sum' }) # Appiattisci multi-indice monthly_report.columns = ['_'.join(col).strip() for col in monthly_report.columns.values] # Aggiungi metriche derivate monthly_report['Sales_Growth_Pct'] = monthly_report['Sales_sum'].pct_change() * 100 monthly_report['Marketing_ROI'] = monthly_report['Sales_sum'] / monthly_report['Marketing_Spend_sum'] print("📊 REPORT MENSILE COMPLETO:") print(monthly_report.round(2)) # Salva su CSV monthly_report.to_csv('time_series_monthly_report.csv') print("\n✅ Report salvato in 'time_series_monthly_report.csv'") print("\n🎉 ANALISI TIME SERIES COMPLETATA!") print("\n📈 KEY INSIGHTS:") print(f"1. Trend generale: {'Crescente' if trend[-1] > trend[0] else 'Decrescente'}") print(f"2. Variazione media giornaliera: {df_ts['Sales_Daily_Change'].mean():.2f}") print(f"3. Weekend vs Weekday: {weekend_stats.loc[True, 'mean']/weekend_stats.loc[False, 'mean']:.2f}x") print(f"4. Lag marketing ottimale: {optimal_lag} giorni") print(f"5. Forecast prossimo mese: {forecast_next_month:.0f}")

⏱️ Funzioni Time Series Essenziali:

  • pd.date_range(): Crea range di date
  • .resample(): Cambia frequenza dati
  • .rolling(): Statistiche mobili
  • .shift(): Sposta dati temporali
  • .diff(): Calcola differenze
  • .pct_change(): Variazioni percentuali
  • dt accessor: Estrae giorno, mese, anno, etc.

💪 Esercizi Avanzati

Esercizio 1: Analisi E-commerce MEDIO

Hai 3 dataset di un e-commerce:

  1. orders.csv: Ordini con ID, Data, Cliente_ID, Totale
  2. customers.csv: Clienti con ID, Nome, Città, Data_Iscrizione
  3. products.csv: Prodotti con ID, Nome, Categoria, Prezzo

Analisi richieste:

  1. Unisci i 3 dataset
  2. Calcola Customer Lifetime Value (CLV) per cliente
  3. Identifica prodotti più venduti per categoria
  4. Analizza stagionalità degli acquisti
  5. Crea cohort analysis per retention rate

Esercizio 2: Analisi Finanziaria DIFFICILE

Dataset prezzi azionari giornalieri (CSV con: Data, Azienda, Apertura, Chiusura, Volume).

Calcoli richiesti:

  1. Calcola rendimenti giornalieri
  2. Moving average 20 e 50 giorni
  3. Volatilità rolling (deviazione standard 30 giorni)
  4. Correlazione tra azioni
  5. Backtest strategia di trading semplice
  6. Creare dashboard pivot interattiva

Esercizio 3: Data Pipeline Completa EXPERT

Crea una pipeline dati end-to-end:

  1. Importa dati da API pubblica (es: COVID, meteo, finanziari)
  2. Pulizia automatica con funzioni custom
  3. Feature engineering avanzato
  4. Resampling per varie frequenze
  5. Analisi statistica completa
  6. Esportazione in report Excel multi-sheet

🎓 Riepilogo Competenze Acquisite

🧹 Data Cleaning Pro

Pulizia automatica, gestione missing values, outlier detection, normalizzazione dati

🔗 Merge & Join Expert

INNER, LEFT, RIGHT, FULL joins, concatenazione, merge su indici, gestione chiavi multiple

📊 Pivot Master

Tabelle pivot multi-livello, crosstab, aggregazioni complesse, analisi multidimensionale

⏱️ Time Series Analyst

Resampling, rolling statistics, decomposizione stagionale, forecasting base, lag analysis

🚀 Pronto per il Machine Learning!

Ora che sai pulire, trasformare e analizzare dati come un professionista, sei pronto per il Machine Learning.

Nel Modulo 3 inizieremo con:

  • 🧠 Concetti base di Machine Learning
  • 📈 Regressione Lineare semplice
  • 🎯 Valutazione modelli
  • 🔍 Feature engineering per ML
Vai al Machine Learning →

📚 Risorse Avanzate

Librerie Utili:

  • pandas-profiling: Analisi automatica dataset
  • missingno: Visualizzazione valori mancanti
  • plotly: Visualizzazioni interattive
  • statsmodels: Analisi statistica avanzata