Guida Pratica: 6 Esercizi Python con Pandas e SQLite per l’Analisi Dati

Cerca:

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
Esercizi Python con Pandas e SQLite per l'Analisi Dati

Oggi, i dati sono il motore di quasi ogni decisione, ma spesso risiedono “bloccati” dentro i database. Per chi usa Python, il problema non è se estrarli, ma come farlo in modo efficace. La combinazione di SQLite e Pandas è una delle più potenti per questo compito: il primo estrae i dati in modo chirurgico, il secondo li trasforma in insight.

Ma la teoria serve a poco senza la pratica.

Questa guida non è un elenco di comandi, ma un percorso pratico. Attraverso 6 scenari lavorativi realistici, passerai dall’interrogare un semplice database di vendite alla costruzione di un sistema di reporting automatizzato. Iniziamo dal primo scenario.

Pubblicità

Esercizio 1: Analisi di un E-commerce Base

Scenario:

Sei un analista junior in un e-commerce di libri. Devi analizzare le vendite del primo trimestre per identificare i libri più popolari.

Soluzione:

import sqlite3
import pandas as pd

# Creazione del database e inserimento dati
conn = sqlite3.connect('libreria.db')
cursor = conn.cursor()

# Creazione tabella vendite
cursor.execute('''
CREATE TABLE IF NOT EXISTS vendite (
    id INTEGER PRIMARY KEY,
    titolo TEXT NOT NULL,
    autore TEXT NOT NULL,
    genere TEXT NOT NULL,
    copie_vendute INTEGER,
    mese TEXT
)
''')

# Inserimento dati di esempio
dati_vendite = [
    (1, 'Il Nome del Vento', 'Patrick Rothfuss', 'Fantasy', 150, 'Gennaio'),
    (2, 'Harry Potter', 'J.K. Rowling', 'Fantasy', 200, 'Gennaio'),
    (3, '1984', 'George Orwell', 'Distopia', 80, 'Gennaio'),
    (4, 'Il Nome del Vento', 'Patrick Rothfuss', 'Fantasy', 120, 'Febbraio'),
    (5, 'Harry Potter', 'J.K. Rowling', 'Fantasy', 180, 'Febbraio'),
    (6, 'Orgoglio e Pregiudizio', 'Jane Austen', 'Romanzo', 90, 'Febbraio'),
    (7, 'Il Nome del Vento', 'Patrick Rothfuss', 'Fantasy', 110, 'Marzo'),
    (8, '1984', 'George Orwell', 'Distopia', 95, 'Marzo'),
    (9, 'Il Grande Gatsby', 'F. Scott Fitzgerald', 'Romanzo', 70, 'Marzo')]

cursor.executemany('INSERT INTO vendite VALUES (?, ?, ?, ?, ?, ?)', dati_vendite)
conn.commit()

# ANALISI CON PANDAS
# Caricamento dati in DataFrame
query = "SELECT * FROM vendite"
df_vendite = pd.read_sql_query(query, conn)

print("=== DATASET COMPLETO ===")
print(df_vendite)
print("\n")

# 1. Vendite totali per libro
vendite_per_libro = df_vendite.groupby('titolo')['copie_vendute'].sum().sort_values(ascending=False)
print("=== VENDITE TOTALI PER LIBRO ===")
print(vendite_per_libro)
print("\n")

# 2. Genere più venduto
genere_popolare = df_vendite.groupby('genere')['copie_vendute'].sum().idxmax()
vendite_genere = df_vendite.groupby('genere')['copie_vendute'].sum().max()
print(f"Genere più venduto: {genere_popolare} con {vendite_genere} copie")

conn.close()

Output atteso:

=== DATASET COMPLETO ===
   id               titolo               autore    genere  copie_vendute    mese
0   1     Il Nome del Vento    Patrick Rothfuss    Fantasy            150  Gennaio
1   2          Harry Potter        J.K. Rowling    Fantasy            200  Gennaio
2   3                  1984      George Orwell   Distopia             80  Gennaio
3   4     Il Nome del Vento    Patrick Rothfuss    Fantasy            120  Febbraio
4   5          Harry Potter        J.K. Rowling    Fantasy            180  Febbraio
5   6  Orgoglio e Pregiudizio     Jane Austen     Romanzo              90  Febbraio
6   7     Il Nome del Vento    Patrick Rothfuss    Fantasy            110  Marzo
7   8                  1984      George Orwell   Distopia             95  Marzo
8   9    Il Grande Gatsby  F. Scott Fitzgerald     Romanzo             70  Marzo

=== VENDITE TOTALI PER LIBRO ===
titolo
Il Nome del Vento    380
Harry Potter         380
1984                 175
Orgoglio e Pregiudizio    90
Il Grande Gatsby     70
Name: copie_vendute, dtype: int64

Genere più venduto: Fantasy con 760 copie

Osservazioni:

💡 Il metodo groupby() permette di aggregare dati per categorie, mentre sum() calcola la somma. Combinarli è fondamentale per analisi di business.

Pubblicità

Esercizio 2: Gestione Inventario con JOIN

Scenario:

L’e-commerce si espande e ora gestisce anche informazioni sugli editori. Devi analizzare le prestazioni degli editori.

Soluzione:

import sqlite3
import pandas as pd

conn = sqlite3.connect('libreria_avanzata.db')
cursor = conn.cursor()

# Tabelle correlate
cursor.execute('''
CREATE TABLE IF NOT EXISTS libri (
    id INTEGER PRIMARY KEY,
    titolo TEXT NOT NULL,
    autore TEXT NOT NULL,
    editore_id INTEGER,
    prezzo REAL
)
''')

cursor.execute('''
CREATE TABLE IF NOT EXISTS editori (
    id INTEGER PRIMARY KEY,
    nome_editore TEXT NOT NULL,
    citta TEXT
)
''')

cursor.execute('''
CREATE TABLE IF NOT EXISTS vendite_dettaglio (
    id INTEGER PRIMARY KEY,
    libro_id INTEGER,
    data_vendita TEXT,
    quantita INTEGER
)
''')

# Inserimento dati
editori = [
    (1, 'Mondadori', 'Milano'),
    (2, 'Einaudi', 'Torino'),
    (3, 'Feltrinelli', 'Milano')]

libri = [
    (1, 'Il Nome del Vento', 'Patrick Rothfuss', 1, 18.50),
    (2, 'Harry Potter', 'J.K. Rowling', 2, 15.00),
    (3, '1984', 'George Orwell', 1, 12.00),
    (4, 'Orgoglio e Pregiudizio', 'Jane Austen', 3, 10.50)]

vendite = [
    (1, 1, '2024-01-15', 5),
    (2, 2, '2024-01-20', 3),
    (3, 1, '2024-02-10', 4),
    (4, 3, '2024-02-15', 2),
    (5, 4, '2024-03-01', 6)]

cursor.executemany('INSERT INTO editori VALUES (?, ?, ?)', editori)
cursor.executemany('INSERT INTO libri VALUES (?, ?, ?, ?, ?)', libri)
cursor.executemany('INSERT INTO vendite_dettaglio VALUES (?, ?, ?, ?)', vendite)
conn.commit()

# ANALISI CON JOIN
query_complessa = '''
SELECT 
    e.nome_editore,
    l.titolo,
    l.autore,
    l.prezzo,
    v.quantita,
    (l.prezzo * v.quantita) as fatturato
FROM vendite_dettaglio v
JOIN libri l ON v.libro_id = l.id
JOIN editori e ON l.editore_id = e.id
'''

df_vendite_complete = pd.read_sql_query(query_complessa, conn)
print("=== VENDITE CON DETTAGLI EDITORI ===")
print(df_vendite_complete)
print("\n")

# Fatturato per editore
fatturato_editore = df_vendite_complete.groupby('nome_editore')['fatturato'].sum()
print("=== FATTURATO PER EDITORE ===")
print(fatturato_editore)

conn.close()

Output atteso:

=== VENDITE CON DETTAGLI EDITORI ===
  nome_editore              titolo           autore  prezzo  quantita  fatturato
0    Mondadori  Il Nome del Vento  Patrick Rothfuss    18.5         5       92.5
1      Einaudi       Harry Potter      J.K. Rowling    15.0         3       45.0
2    Mondadori  Il Nome del Vento  Patrick Rothfuss    18.5         4       74.0
3    Mondadori               1984     George Orwell    12.0         2       24.0
4  Feltrinelli  Orgoglio e Pregiudizio    Jane Austen    10.5         6       63.0

=== FATTURATO PER EDITORE ===
nome_editore
Einaudi       45.0
Feltrinelli   63.0
Mondadori     190.5
Name: fatturato, dtype: float64

Osservazioni:

💡 Le JOIN SQL permettono di combinare dati da tabelle diverse. In Pandas, possiamo eseguire JOIN direttamente nel SQL query prima di caricare i dati nel DataFrame.

 


Esercizio 3: Analisi Temporale delle Vendite

Scenario:

Devi analizzare l’andamento delle vendite nel tempo per identificare stagionalità e trend.

Soluzione:

import sqlite3
import pandas as pd
from datetime import datetime

conn = sqlite3.connect('vendite_temporali.db')
cursor = conn.cursor()

cursor.execute('''
CREATE TABLE IF NOT EXISTS vendite_temporali (
    id INTEGER PRIMARY KEY,
    prodotto TEXT,
    data_vendita DATE,
    quantita INTEGER,
    prezzo_unitario REAL
)
''')

# Generazione dati temporali
vendite_data = [
    (1, 'Libro A', '2024-01-05', 10, 15.00),
    (2, 'Libro B', '2024-01-12', 5, 20.00),
    (3, 'Libro A', '2024-01-19', 8, 15.00),
    (4, 'Libro C', '2024-02-02', 12, 12.50),
    (5, 'Libro B', '2024-02-09', 6, 20.00),
    (6, 'Libro A', '2024-02-16', 15, 15.00),
    (7, 'Libro C', '2024-03-01', 7, 12.50),
    (8, 'Libro A', '2024-03-08', 11, 15.00),
    (9, 'Libro B', '2024-03-15', 9, 20.00)]

cursor.executemany('INSERT INTO vendite_temporali VALUES (?, ?, ?, ?, ?)', vendite_data)
conn.commit()

# Caricamento e analisi temporale
df_temporale = pd.read_sql_query("SELECT * FROM vendite_temporali", conn)

# Conversione a datetime
df_temporale['data_vendita'] = pd.to_datetime(df_temporale['data_vendita'])
df_temporale['fatturato'] = df_temporale['quantita'] * df_temporale['prezzo_unitario']

print("=== DATASET CON DATA CONVERTITA ===")
print(df_temporale.dtypes)
print("\n")

# Vendite mensili
df_temporale['mese'] = df_temporale['data_vendita'].dt.to_period('M')
vendite_mensili = df_temporale.groupby('mese')['fatturato'].sum()
print("=== VENDITE MENSILI ===")
print(vendite_mensili)
print("\n")

# Trend prodotto A
prodotto_a = df_temporale[df_temporale['prodotto'] == 'Libro A']
trend_a = prodotto_a.groupby('mese')['quantita'].sum()
print("=== TREND LIBRO A ===")
print(trend_a)

conn.close()

Output atteso:

=== DATASET CON DATA CONVERTITA ===
id                       int64
prodotto                object
data_vendita    datetime64[ns]
quantita                 int64
prezzo_unitario        float64
fatturato              float64
dtype: object

=== VENDITE MENSILI ===
mese
2024-01    310.0
2024-02    387.5
2024-03    385.0
Freq: M, Name: fatturato, dtype: float64

=== TREND LIBRO A ===
mese
2024-01    18
2024-02    15
2024-03    11
Freq: M, Name: quantita, dtype: int64

Osservazioni:

💡 La conversione a datetime permette di utilizzare potenti funzioni di analisi temporale come dt.to_period() per raggruppare per mese/anno.

Forse potrebbe interessarti anche:  La Matrice di Confusione Spiegata: Guida Completa a TP, TN, FP, FN e Valutazione Modelli di Classificazione

Esercizio 4: Pulizia Dati e Gestione Valori Mancanti

Scenario:

Ricevi un dataset di vendite con dati incompleti. Devi pulire i dati prima dell’analisi.

Soluzione:

import sqlite3
import pandas as pd
import numpy as np

conn = sqlite3.connect('dati_sporchi.db')
cursor = conn.cursor()

cursor.execute('''
CREATE TABLE IF NOT EXISTS vendite_sporche (
    id INTEGER PRIMARY KEY,
    cliente TEXT,
    prodotto TEXT,
    quantita INTEGER,
    prezzo REAL,
    data_acquisto TEXT
)
''')

# Dati con problemi intenzionali
dati_sporchi = [
    (1, 'Mario Rossi', 'Libro X', 2, 15.00, '2024-01-10'),
    (2, None, 'Libro Y', 1, 20.00, '2024-01-15'),  # Cliente mancante
    (3, 'Luisa Verdi', 'Libro Z', None, 18.50, '2024-01-20'),  # Quantità mancante
    (4, 'Giulia Neri', 'Libro X', 3, None, '2024-02-05'),  # Prezzo mancante
    (5, 'Marco Bianchi', None, 2, 12.00, '2024-02-10'),  # Prodotto mancante
    (6, 'Anna Gialli', 'Libro Y', 1, 20.00, 'data_errata')  # Data errata
]

cursor.executemany('INSERT INTO vendite_sporche VALUES (?, ?, ?, ?, ?, ?)', dati_sporchi)
conn.commit()

# Caricamento e pulizia
df_sporco = pd.read_sql_query("SELECT * FROM vendite_sporche", conn)

print("=== DATASET ORIGINALE ===")
print(df_sporco)
print(f"Shape originale: {df_sporco.shape}")
print("\n")

# 1. Identificazione valori mancanti
valori_mancanti = df_sporco.isnull().sum()
print("=== VALORI MANCANTI ===")
print(valori_mancanti)
print("\n")

# 2. Pulizia strategica
df_pulito = df_sporco.copy()

# Rimuovere righe con prodotto mancante (non recuperabile)
df_pulito = df_pulito.dropna(subset=['prodotto'])

# Riempire quantità mancante con la mediana
quantita_mediana = df_pulito['quantita'].median()
df_pulito['quantita'] = df_pulito['quantita'].fillna(quantita_mediana)

# Riempire prezzo mancante con la media del prodotto
prezzo_medio_x = df_pulito[df_pulito['prodotto'] == 'Libro X']['prezzo'].mean()
df_pulito.loc[df_pulito['prodotto'] == 'Libro X', 'prezzo'] = df_pulito.loc[df_pulito['prodotto'] == 'Libro X', 'prezzo'].fillna(prezzo_medio_x)

# Cliente mancante: assegnare "Cliente Sconosciuto"
df_pulito['cliente'] = df_pulito['cliente'].fillna('Cliente Sconosciuto')

# Correzione data errata
df_pulito['data_acquisto'] = pd.to_datetime(df_pulito['data_acquisto'], errors='coerce')
df_pulito = df_pulito.dropna(subset=['data_acquisto'])

print("=== DATASET PULITO ===")
print(df_pulito)
print(f"Shape dopo pulizia: {df_pulito.shape}")
print("\n")

# Calcolo fatturato dopo pulizia
df_pulito['fatturato'] = df_pulito['quantita'] * df_pulito['prezzo']
print("=== FATTURATO TOTALE ===")
print(f"Fatturato totale: €{df_pulito['fatturato'].sum():.2f}")

conn.close()

Output atteso:

=== DATASET ORIGINALE ===
   id        cliente prodotto  quantita  prezzo data_acquisto
0   1    Mario Rossi  Libro X       2.0    15.0    2024-01-10
1   2           None  Libro Y       1.0    20.0    2024-01-15
2   3    Luisa Verdi  Libro Z       NaN    18.5    2024-01-20
3   4    Giulia Neri  Libro X       3.0     NaN    2024-02-05
4   5  Marco Bianchi     None       2.0    12.0    2024-02-10
5   6    Anna Gialli  Libro Y       1.0    20.0   data_errata
Shape originale: (6, 6)


=== VALORI MANCANTI ===
id               0
cliente          1
prodotto         1
quantita         1
prezzo           1
data_acquisto    0
dtype: int64


=== DATASET PULITO ===
   id              cliente prodotto  quantita  prezzo data_acquisto
0   1          Mario Rossi  Libro X       2.0    15.0    2024-01-10
1   2  Cliente Sconosciuto  Libro Y       1.0    20.0    2024-01-15
2   3          Luisa Verdi  Libro Z       1.5    18.5    2024-01-20
3   4          Giulia Neri  Libro X       3.0    15.0    2024-02-05
Shape dopo pulizia: (4, 6)


=== FATTURATO TOTALE ===
Fatturato totale: €122.75

Osservazioni:

💡 La gestione dei valori mancanti richiede strategie diverse a seconda del contesto. fillna() con statistiche appropriate è spesso meglio della semplice rimozione.

Pubblicità

Esercizio 5: Analisi Avanzata con Query Complesse e Sottotabelle

Scenario:

Sei promosso ad analista senior. Devi creare un report completo con metriche multiple.

Soluzione:

import sqlite3
import pandas as pd

def crea_database_e_tabelle():
    """Crea il database e le tabelle in una funzione separata"""
    conn = sqlite3.connect('analisi_avanzata.db')
    cursor = conn.cursor()

    # Schema complesso con gestione errori
    try:
        # Tabelle correlate
        cursor.execute('''
        CREATE TABLE IF NOT EXISTS prodotti (
            prodotto_id INTEGER PRIMARY KEY,
            nome TEXT,
            categoria TEXT,
            prezzo_listino REAL
        )
        ''')

        cursor.execute('''
        CREATE TABLE IF NOT EXISTS vendite_avanzate (
            vendita_id INTEGER PRIMARY KEY,
            prodotto_id INTEGER,
            data DATE,
            quantita INTEGER,
            prezzo_vendita REAL,
            sconto_applicato REAL,
            FOREIGN KEY (prodotto_id) REFERENCES prodotti(prodotto_id)
        )
        ''')

        cursor.execute('''
        CREATE TABLE IF NOT EXISTS clienti (
            cliente_id INTEGER PRIMARY KEY,
            nome TEXT,
            regione TEXT,
            tipo_cliente TEXT
        )
        ''')

        cursor.execute('''
        CREATE TABLE IF NOT EXISTS vendite_clienti (
            vendita_id INTEGER,
            cliente_id INTEGER,
            FOREIGN KEY (vendita_id) REFERENCES vendite_avanzate(vendita_id),
            FOREIGN KEY (cliente_id) REFERENCES clienti(cliente_id)
        )
        ''')

        # Inserimento dati prodotti
        prodotti = [
            (1, 'Libro Fantasy A', 'Fantasy', 20.00),
            (2, 'Libro Romanzo B', 'Romanzo', 15.00),
            (3, 'Libro Giallo C', 'Giallo', 18.00),
            (4, 'Libro Fantasy D', 'Fantasy', 22.00)
        ]
        cursor.executemany('INSERT INTO prodotti VALUES (?, ?, ?, ?)', prodotti)

        # Inserimento dati vendite
        vendite = [
            (1, 1, '2024-01-10', 2, 18.00, 2.00),
            (2, 2, '2024-01-15', 1, 14.00, 1.00),
            (3, 1, '2024-01-20', 3, 17.50, 2.50),
            (4, 3, '2024-02-05', 2, 16.00, 2.00),
            (5, 4, '2024-02-10', 1, 20.00, 2.00),
            (6, 2, '2024-02-15', 2, 13.50, 1.50)
        ]
        cursor.executemany('INSERT INTO vendite_avanzate VALUES (?, ?, ?, ?, ?, ?)', vendite)

        # Inserimento dati clienti
        clienti = [
            (1, 'Mario Rossi', 'Nord', 'Premium'),
            (2, 'Luisa Verdi', 'Centro', 'Standard'),
            (3, 'Giulia Neri', 'Sud', 'Premium')
        ]
        cursor.executemany('INSERT INTO clienti VALUES (?, ?, ?, ?)', clienti)

        # Inserimento relazione vendite-clienti
        vendite_clienti_data = [
            (1, 1), (2, 2), (3, 1), (4, 3), (5, 2), (6, 1)
        ]
        cursor.executemany('INSERT INTO vendite_clienti VALUES (?, ?)', vendite_clienti_data)

        conn.commit()
        print("✅ Database e tabelle creati con successo!")
        
    except sqlite3.Error as e:
        print(f"❌ Errore durante la creazione del database: {e}")
        conn.rollback()
    finally:
        conn.close()

# SOLUZIONE 1: Creare prima il database, poi analizzare
crea_database_e_tabelle()

# SOLUZIONE 2: Usare context manager per gestire automaticamente le connessioni
def analisi_avanzata():
    """Esegue l'analisi avanzata usando context manager"""
    
    with sqlite3.connect('analisi_avanzata.db') as conn:
        # QUERY AVANZATA: Multiple metriche
        query_avanzata = '''
        SELECT 
            p.categoria,
            COUNT(DISTINCT v.vendita_id) as numero_vendite,
            SUM(v.quantita) as totale_quantita,
            SUM(v.quantita * v.prezzo_vendita) as fatturato_totale,
            AVG(v.prezzo_vendita) as prezzo_medio_vendita,
            SUM(v.sconto_applicato * v.quantita) as sconto_totale,
            COUNT(DISTINCT vc.cliente_id) as clienti_unici
        FROM prodotti p
        JOIN vendite_avanzate v ON p.prodotto_id = v.prodotto_id
        JOIN vendite_clienti vc ON v.vendita_id = vc.vendita_id
        GROUP BY p.categoria
        '''

        df_analisi_avanzata = pd.read_sql_query(query_avanzata, conn)
        
        print("=== ANALISI AVANZATA PER CATEGORIA ===")
        print(df_analisi_avanzata)
        print("\n")

        # Analisi aggiuntiva con Pandas
        df_analisi_avanzata['fatturato_medio_per_vendita'] = (
            df_analisi_avanzata['fatturato_totale'] / df_analisi_avanzata['numero_vendite']
        )
        df_analisi_avanzata['sconto_percentuale'] = (
            df_analisi_avanzata['sconto_totale'] / df_analisi_avanzata['fatturato_totale'] * 100
        )

        print("=== METRICHE AGGIUNTE ===")
        print(df_analisi_avanzata[['categoria', 'fatturato_medio_per_vendita', 'sconto_percentuale']])
        print("\n")
        
        return df_analisi_avanzata

# SOLUZIONE 3: Analisi dettagliata con query separate
def analisi_dettagliata():
    """Analisi più dettagliata con query multiple"""
    
    with sqlite3.connect('analisi_avanzata.db') as conn:
        # Query 1: Performance per prodotto
        query_prodotti = '''
        SELECT 
            p.nome,
            p.categoria,
            SUM(v.quantita) as vendite_totali,
            SUM(v.quantita * v.prezzo_vendita) as fatturato,
            AVG(v.prezzo_vendita) as prezzo_medio
        FROM prodotti p
        JOIN vendite_avanzate v ON p.prodotto_id = v.prodotto_id
        GROUP BY p.nome, p.categoria
        ORDER BY fatturato DESC
        '''
        
        df_prodotti = pd.read_sql_query(query_prodotti, conn)
        print("=== PERFORMANCE PER PRODOTTO ===")
        print(df_prodotti)
        print("\n")

        # Query 2: Clienti premium vs standard
        query_clienti = '''
        SELECT 
            c.tipo_cliente,
            COUNT(DISTINCT c.cliente_id) as numero_clienti,
            SUM(v.quantita) as prodotti_acquistati,
            SUM(v.quantita * v.prezzo_vendita) as fatturato_totale
        FROM clienti c
        JOIN vendite_clienti vc ON c.cliente_id = vc.cliente_id
        JOIN vendite_avanzate v ON vc.vendita_id = v.vendita_id
        GROUP BY c.tipo_cliente
        '''
        
        df_clienti = pd.read_sql_query(query_clienti, conn)
        print("=== ANALISI PER TIPO CLIENTE ===")
        print(df_clienti)

# Esecuzione delle analisi
print("🎯 ESERCIZIO 5: ANALISI AVANZATA CON QUERY COMPLESSE")
print("=" * 60)

df_risultati = analisi_avanzata()
analisi_dettagliata()

# Analisi aggiuntiva con Pandas
print("=== ANALISI AVANZATA PANDAS ===")
print("📊 Statistiche descrittive del fatturato:")
print(f"Fatturato totale: €{df_risultati['fatturato_totale'].sum():.2f}")
print(f"Fatturato medio per categoria: €{df_risultati['fatturato_totale'].mean():.2f}")
print(f"Categoria con fatturato massimo: {df_risultati.loc[df_risultati['fatturato_totale'].idxmax(), 'categoria']}")
print(f"Sconto medio applicato: {df_risultati['sconto_percentuale'].mean():.2f}%")

Output atteso:


🎯 ESERCIZIO 5: ANALISI AVANZATA CON QUERY COMPLESSE
============================================================
=== ANALISI AVANZATA PER CATEGORIA ===
  categoria  numero_vendite  totale_quantita  fatturato_totale  \
0   Fantasy               3                6             108.5   
1    Giallo               1                2              32.0   
2   Romanzo               2                3              41.0   

   prezzo_medio_vendita  sconto_totale  clienti_unici  
0                 18.50           13.5              2  
1                 16.00            4.0              1  
2                 13.75            4.0              2  


=== METRICHE AGGIUNTE ===
  categoria  fatturato_medio_per_vendita  sconto_percentuale
0   Fantasy                    36.166667           12.442396
1    Giallo                    32.000000           12.500000
2   Romanzo                    20.500000            9.756098


=== PERFORMANCE PER PRODOTTO ===
              nome categoria  vendite_totali  fatturato  prezzo_medio
0  Libro Fantasy A   Fantasy               5       88.5         17.75
1  Libro Romanzo B   Romanzo               3       41.0         13.75
2   Libro Giallo C    Giallo               2       32.0         16.00
3  Libro Fantasy D   Fantasy               1       20.0         20.00


=== ANALISI PER TIPO CLIENTE ===
  tipo_cliente  numero_clienti  prodotti_acquistati  fatturato_totale
0      Premium               2                    9             147.5
1     Standard               1                    2              34.0
=== ANALISI AVANZATA PANDAS ===
📊 Statistiche descrittive del fatturato:
Fatturato totale: €181.50
Fatturato medio per categoria: €60.50
Categoria con fatturato massimo: Fantasy
Sconto medio applicato: 11.57%

Osservazioni:

💡 Le query SQL complesse possono calcolare multiple metriche in una singola esecuzione, mentre Pandas è ottimo per calcoli aggiuntivi e manipolazioni.

Forse potrebbe interessarti anche:  Selenium oltre le Basi: 3 Esercizi Pratici per l'Automazione Web Avanzata

 


Esercizio 6: Sistema Completo di Reporting con Esportazione

Scenario:

Devi creare un sistema di reporting automatizzato che genera report in diversi formati.

Soluzione:

import sqlite3
import pandas as pd
import matplotlib.pyplot as plt
import os

# Creazione directory per report
os.makedirs('report', exist_ok=True)

conn = sqlite3.connect('reporting_system.db')
cursor = conn.cursor()

# Database per reporting
cursor.execute('''
CREATE TABLE IF NOT EXISTS vendite_reporting (
    id INTEGER PRIMARY KEY,
    regione TEXT,
    prodotto TEXT,
    trimestre TEXT,
    vendite INTEGER,
    budget INTEGER
)
''')

# Dati di vendite e budget
dati_reporting = [
    (1, 'Nord', 'Libro A', 'Q1', 1200, 1000),
    (2, 'Nord', 'Libro B', 'Q1', 800, 900),
    (3, 'Centro', 'Libro A', 'Q1', 950, 800),
    (4, 'Centro', 'Libro B', 'Q1', 700, 750),
    (5, 'Sud', 'Libro A', 'Q1', 600, 500),
    (6, 'Sud', 'Libro B', 'Q1', 400, 450),
    (7, 'Nord', 'Libro A', 'Q2', 1300, 1100),
    (8, 'Nord', 'Libro B', 'Q2', 850, 950),
    (9, 'Centro', 'Libro A', 'Q2', 1000, 850),
    (10, 'Centro', 'Libro B', 'Q2', 750, 800),
    (11, 'Sud', 'Libro A', 'Q2', 650, 550),
    (12, 'Sud', 'Libro B', 'Q2', 450, 500)]

cursor.executemany('INSERT INTO vendite_reporting VALUES (?, ?, ?, ?, ?, ?)', dati_reporting)
conn.commit()

# SISTEMA DI REPORTING COMPLETO
class ReportingSystem:
    def __init__(self, db_connection):
        self.conn = db_connection
        self.reports = {}
    
    def carica_dati(self):
        """Carica tutti i dati per l'analisi"""
        query = "SELECT * FROM vendite_reporting"
        self.df_completo = pd.read_sql_query(query, self.conn)
        
        # Calcolo metriche aggiuntive
        self.df_completo['performance'] = (
            self.df_completo['vendite'] / self.df_completo['budget'] * 100
        )
        self.df_completo['scostamento'] = (
            self.df_completo['vendite'] - self.df_completo['budget']
        )
    
    def genera_report_regioni(self):
        """Report performance per regione"""
        report_regioni = self.df_completo.groupby('regione').agg({
            'vendite': 'sum',
            'budget': 'sum',
            'performance': 'mean'
        }).round(2)
        
        report_regioni['performance_totale'] = (
            report_regioni['vendite'] / report_regioni['budget'] * 100
        ).round(2)
        
        self.reports['regioni'] = report_regioni
        return report_regioni
    
    def genera_report_prodotti(self):
        """Report performance per prodotto"""
        report_prodotti = self.df_completo.groupby('prodotto').agg({
            'vendite': 'sum',
            'budget': 'sum',
            'performance': 'mean'
        }).round(2)
        
        self.reports['prodotti'] = report_prodotti
        return report_prodotti
    
    def analisi_trimestrale(self):
        """Analisi dettagliata trimestrale"""
        pivot_vendite = pd.pivot_table(
            self.df_completo,
            values='vendite',
            index='prodotto',
            columns='trimestre',
            aggfunc='sum'
        )
        
        pivot_budget = pd.pivot_table(
            self.df_completo,
            values='budget',
            index='prodotto',
            columns='trimestre',
            aggfunc='sum'
        )
        
        self.reports['pivot_vendite'] = pivot_vendite
        self.reports['pivot_budget'] = pivot_budget
        
        return pivot_vendite, pivot_budget
    
    def esporta_report(self):
        """Esporta tutti i report in diversi formati"""
        # CSV
        for nome, report in self.reports.items():
            filename = f'report/{nome}_report.csv'
            report.to_csv(filename)
            print(f"Report {nome} esportato in: {filename}")
        
        # Excel con multiple sheets
        with pd.ExcelWriter('report/report_completo.xlsx') as writer:
            for nome, report in self.reports.items():
                report.to_excel(writer, sheet_name=nome[:31])  # Limite caratteri Excel
        
        print("Report Excel completo creato: report/report_completo.xlsx")
    
    def crea_grafico_performance(self):
        """Crea grafico delle performance"""
        plt.figure(figsize=(12, 6))
        
        report_regioni = self.reports['regioni']
        regioni = report_regioni.index
        performance = report_regioni['performance_totale']
        
        plt.bar(regioni, performance, color=['green' if x >= 100 else 'red' for x in performance])
        plt.axhline(y=100, color='blue', linestyle='--', label='Target 100%')
        plt.title('Performance per Regione (%)')
        plt.ylabel('Performance %')
        plt.legend()
        
        plt.savefig('report/performance_regioni.png', dpi=300, bbox_inches='tight')
        plt.close()
        print("Grafico creato: report/performance_regioni.png")

# ESECUZIONE SISTEMA
sistema = ReportingSystem(conn)
sistema.carica_dati()

print("=== REPORT REGIONI ===")
print(sistema.genera_report_regioni())
print("\n")

print("=== REPORT PRODOTTI ===")
print(sistema.genera_report_prodotti())
print("\n")

print("=== ANALISI TRIMESTRALE ===")
vendite_trim, budget_trim = sistema.analisi_trimestrale()
print("Vendite per trimestre:")
print(vendite_trim)
print("\nBudget per trimestre:")
print(budget_trim)

# Esportazione
sistema.esporta_report()
sistema.crea_grafico_performance()

conn.close()

print("\n=== SISTEMA DI REPORTING COMPLETATO ===")
print("Tutti i report sono stati generati nella cartella 'report/'")

Output atteso:

=== REPORT REGIONI ===
        vendite  budget  performance  performance_totale
regione                                                
Centro     3400    3200       112.92              106.25
Nord       4250    4000       110.12              106.25
Sud        2100    2000       111.67              105.00

=== REPORT PRODOTTI ===
          vendite  budget  performance
prodotto                              
Libro A      4100    3750       113.61
Libro B      2800    3000       108.61

=== ANALISI TRIMESTRALE ===
Vendite per trimestre:
trimestre    Q1    Q2
prodotto             
Libro A    2750  2950
Libro B    1900  1800

Budget per trimestre:
trimestre    Q1    Q2
prodotto             
Libro A    2300  2450
Libro B    2100  2250
...

Report regioni esportato in: report/regioni_report.csv
Report prodotti esportato in: report/prodotti_report.csv
Report pivot_vendite esportato in: report/pivot_vendite_report.csv
Report pivot_budget esportato in: report/pivot_budget_report.csv
Report Excel completo creato: report/report_completo.xlsx
Grafico creato: report/performance_regioni.png

=== SISTEMA DI REPORTING COMPLETATO ===
Tutti i report sono stati generati nella cartella 'report/'

Osservazioni:

💡 Un sistema di reporting completo combina SQL per l’estrazione dati, Pandas per l’analisi e manipolazione, e varie librerie per l’esportazione e visualizzazione.

Forse potrebbe interessarti anche:  Chain of Hallucination (CoH): l’evoluzione delle allucinazioni nei modelli linguistici generativi

Commento Applicativo degli Esercizi

Esercizio 1: Analisi di un E-commerce Base

  • Questo è il “pane quotidiano”. È la prima richiesta che riceve un analista: “Quali sono i prodotti più venduti?”.
  • Peculiarità (Perché è interessante): Insegna la pipeline fondamentale: Connect -> Query -> Load -> Analyze. L’uso di pd.read_sql_query è la funzione cardine che unisce i due mondi. Il groupby().sum() è l’operazione di aggregazione più comune. È l’equivalente del “Hello, World!” per la data analysis.

Esercizio 2: Gestione Inventario con JOIN

  • I dati non vivono mai in un’unica tabella. Per calcolare il fatturato (Vendite * Prezzo), è necessario unire la tabella delle vendite con quella dei libri. Per sapere chi ha generato quel fatturato, serve la tabella degli editori.
  • Peculiarità: Questo esercizio dimostra perché è più efficiente eseguire il JOIN in SQL (come fatto nella query_complessa) piuttosto che caricare tre tabelle separate in Pandas e poi usare pd.merge(). Si delega il lavoro pesante di unione al database, che è ottimizzato per farlo.

Esercizio 3: Analisi Temporale delle Vendite

  • Analizzare i totali non basta. Bisogna capire quando avvengono le vendite. C’è stagionalità? Stiamo crescendo mese su mese?
  • Peculiarità: La gestione delle date è cruciale. L’esercizio mostra il modo “Pandas-iano” corretto: (1) Convertire la colonna in un oggetto datetime64[ns] e (2) Usare l’accessor .dt (in questo caso .dt.to_period('M')) per estrarre e raggruppare per periodi. È molto più pulito e potente che manipolare stringhe.

Esercizio 4: Pulizia Dati e Gestione Valori Mancanti

  • Questo è l’esercizio più importante e realistico di tutti. I dati non sono mai puliti. I clienti dimenticano di inserire campi, i sistemi falliscono, le date sono corrotte.
  • Peculiarità: È fantastico perché non si limita a un banale dropna(). Mostra strategie di pulizia contestuali:
    1. Riempire con la mediana: fillna(quantita_mediana) è robusto in caso di outlier (se un cliente avesse comprato 1000 copie, la media sarebbe falsata, la mediana no).
    2. Riempire con una media di gruppo: Il prezzo del “Libro X” viene riempito con la media solo degli altri “Libro X”. Questa è una tecnica avanzata e corretta.
    3. Gestire errori di tipo: pd.to_datetime(errors='coerce') è il modo migliore per convertire le date, trasformando automaticamente i formati errati (‘data_errata’) in NaT (Not a Time), che possono poi essere filtrati.

Esercizio 5: Analisi Avanzata con Query Complesse

  • Questo simula la creazione di un set di KPI (Key Performance Indicators) per una dashboard. L’obiettivo è avere una vista aggregata (per categoria, per tipo cliente) che riassuma la salute del business.
  • Mostra la vera sinergia. La query SQL fa il “lavoro sporco” di aggregazione pesante (COUNT(DISTINCT), AVG, SUM multipli) su più tabelle. Poi, Pandas viene usato per il “lavoro di fino”: calcolare metriche derivate (come sconto_percentuale) che sarebbero state molto complesse da calcolare direttamente in SQL.

Esercizio 6: Sistema Completo di Reporting con Esportazione

  •  Il lavoro di un analista non finisce con un print(). I risultati devono essere comunicati in modo chiaro, condivisibile e ripetibile.
  • Questo è un mini-progetto “capstone”.
    1. OOP (Object-Oriented): Incapsulare la logica in una classe (ReportingSystem) rende il processo riutilizzabile. Domani, basterà cambiare il database e chiamare .carica_dati().
    2. Pivot Table: Mostra pd.pivot_table, uno strumento potente per confrontare metriche (es. Vendite vs Budget per Trimestre).
    3. Output Multi-formato: Esporta sia in CSV che in un singolo file Excel con fogli multipli, una richiesta aziendale incredibilmente comune.
    4. Visualizzazione: Chiude il cerchio creando un grafico (matplotlib) che comunica il risultato (performance vs target) in modo visivo e immediato.

Riepilogo Apprendimento

Concetti Chiave Appresi:

  • Pandas + SQLite3 Integration: Come combinare la potenza di SQL per query complesse con la flessibilità di Pandas per l’analisi
  • Data Cleaning: Strategie per gestire valori mancanti e dati inconsistenti
  • GroupBy Operations: Aggregazione dati per categorie multiple
  • Time Series Analysis: Manipolazione e analisi di dati temporali
  • Multi-Table JOINs: Combinazione di dati da tabelle correlate
  • Advanced Reporting: Creazione di sistemi completi di analisi e reporting

Competenze Sviluppate:

  • Pensiero analitico per problemi di business reali
  • Gestione di dataset complessi e correlati
  • Automazione di processi di reporting
  • Creazione di metriche personalizzate
  • Esportazione risultati in formati diversi

Questi esercizi coprono le competenze essenziali richieste per posizioni di data analysis junior e forniscono una solida base per affrontare problemi reali nel mondo del lavoro.

Pubblicità