Benvenuto al Modulo 5. Abbiamo passato i primi quattro moduli sul linguaggio in sé e sul tooling che gli sta intorno; ora cambiamo marcia e passiamo le prossime dieci lezioni su quello che la maggior parte degli sviluppatori Python che lavorano fa davvero con il linguaggio tutto il giorno, ovvero spingere dati tabulari attraverso trasformazioni. Grosso modo metà dei lavori Python che ho visto nell’ultimo decennio erano, in sostanza, “leggi un file, cambia qualche colonna, scrivi un altro file, manda un messaggio Slack quando si rompe”. Quel lavoro gira su pandas. Il Modulo 5 è la padronanza di pandas; il Modulo 6 è la roba più dura (window function, time series, performance). La lezione 35 è un capitolo dedicato a Polars, che incontreremo brevemente oggi.
Ma prima di toccare un read_csv, dobbiamo parlare di dove pandas si colloca nel 2026, di cosa è cambiato negli ultimi tre anni, e perché le tue vecchie risposte di StackOverflow potrebbero darti consigli che la libreria non sottoscrive più.
Una breve storia, perché il contesto conta
Pandas è stato avviato da Wes McKinney nel 2008 nell’hedge fund AQR. Aveva bisogno di qualcosa tra Excel e un database SQL per dati finanziari pesanti di time series, ha scoperto che ciò che esisteva in Python all’epoca era o NumPy (troppo basso livello) o R-via-rpy2 (troppo goffo), e si è scritto il suo. Lo ha reso open source l’anno successivo, ha lasciato la finanza, e ha passato la maggior parte di due decenni a guidare l’ecosistema dei dati. (Ha anche dato il via al progetto Apache Arrow nel 2016, tienilo a mente, conterà tra cinque paragrafi.)
Per circa quindici anni, pandas è stato la risposta a “ho una tabella in Python”. Non l’unica risposta: c’erano sempre state alternative, da dask per dati out-of-core a PySpark per la scala cluster, ma il default, la cosa che ogni notebook su Kaggle e ogni laptop di data scientist junior afferrava. Ogni libreria adiacente è stata costruita per accettare un DataFrame di pandas: il df.plot() di matplotlib, il fit(X, y) di scikit-learn dove X è di solito un DataFrame, statsmodels, seaborn, plotly, i wrapper SQL-via-DataFrame, i connector di database. La fossa difensiva ecosistemica è enorme, e quello conta per quello che discuteremo tra un attimo.
I problemi sono sempre stati gli stessi. Pandas era costruito sopra NumPy, che non aveva nessun concetto nativo di valori mancanti per colonne intere o booleane (quindi una colonna con un intero mancante diventava float64, con il valore mancante come NaN, sorprendente e sbagliato). Le colonne stringa erano memorizzate come oggetti Python nell’array NumPy, il che voleva dire operazioni su stringhe lente e memoria gonfiata. La semantica di copy-on-write di default era incoerente: a volte ottenevi una vista, a volte una copia, e il famoso SettingWithCopyWarning perseguitava chiunque. Nessuno di questi era fatale, ma si accumulavano.
Pandas 2.0 (2023): la riscrittura silenziosa
Pandas 2.0 è uscito ad aprile 2023 ed è la release più consequenziale dalla 1.0. Il cambiamento principale: un backend PyArrow come alternativa a NumPy sotto il cofano.
Cosa significa in pratica. Apache Arrow è un formato di memoria a colonne progettato per workload analitici. Ha supporto di prima classe per i valori mancanti (ogni tipo è nullable), storage efficiente delle stringhe, scambio veloce e zero-copy tra linguaggi e tool, ed è la lingua franca che DuckDB, Polars, Spark e i moderni data warehouse parlano tutti. Dando a pandas un backend Arrow, i maintainer hanno ottenuto colonne intere nullable, operazioni su stringhe dieci volte più veloci, e un formato di memoria condiviso con il resto del mondo dei dati, senza rompere i milioni di righe di codice pandas esistenti.
Tre cose da sapere su questo a maggio 2026:
È opt-in. Leggere un CSV con pd.read_csv("file.csv") ti dà ancora il backend NumPy. Chiedi Arrow esplicitamente:
import pandas as pd
df = pd.read_csv("sales.csv", dtype_backend="pyarrow")
df = pd.read_parquet("sales.parquet", dtype_backend="pyarrow")
# Oppure globalmente per uno script
pd.options.future.infer_string = True # stringhe arrow-backed di default
Adesso è maturo. Il primo anno del backend Arrow (2023) aveva spigoli ruvidi: alcune operazioni ricadevano su NumPy e copiavano i dati, altre non funzionavano affatto. Per pandas 2.2 (inizio 2024) la maggior parte di quelli era chiusa, e con la serie 2.3 nel 2025 il backend è stabile per le operazioni che un analista normale usa. Se stai iniziando un progetto nuovo nel 2026, pandas con backend Arrow è il default giusto.
Copy-on-write è il nuovo default, ed è un miglioramento vero. Il vecchio “questa è una vista o una copia?” è sparito in pandas 3.0 (rilasciato a fine 2025), e puoi attivarlo già adesso in 2.x con pd.options.mode.copy_on_write = True. Codice nuovo; nuovi default; accendilo.
Polars: l’alternativa in ascesa
Mentre pandas riscriveva la sua tubatura, Polars veniva scritto da zero in Rust da Ritchie Vink. La prima versione è atterrata nel 2020; la versione 1.0 a metà 2024; a maggio 2026 è alla 1.x e abbastanza stabile per la produzione. È lo sfidante più credibile che pandas abbia avuto da quando è iniziata l’era moderna.
Il pitch è facile: Polars è costruito su Arrow dal primo giorno (nessun retaggio NumPy), è multi-thread di default, ha un query optimizer (la modalità lazy pianifica tutta la pipeline prima di eseguirla), ed è scritto in un linguaggio di sistema, quindi i loop interni non pagano la tassa dell’interprete Python. Sulla maggior parte delle operazioni (filtering, join, group-by, aggregazione) Polars è da due a dieci volte più veloce di pandas con il backend Arrow, e usa significativamente meno memoria.
Ha anche un’API più coerente. Pandas ha accumulato quindici anni di decisioni “aggiungiamo anche questo metodo”, portando a tre modi di filtrare le righe, quattro modi di aggiungere una colonna, e un sistema di indici che è genuinamente confuso per i nuovi arrivati. Polars ha reso l’API uniforme: tutto è una expression su una colonna, eseguita nel contesto di un DataFrame.
Confronto rapido di sintassi. Raggruppa delle vendite per regione e calcola la media e il totale, filtrando prima alle transazioni di valore alto:
# pandas
import pandas as pd
df = pd.read_parquet("sales.parquet", dtype_backend="pyarrow")
result = (
df[df["amount"] > 1000]
.groupby("region", as_index=False)
.agg(mean_amount=("amount", "mean"), total=("amount", "sum"))
)
# Polars
import polars as pl
df = pl.read_parquet("sales.parquet")
result = (
df.filter(pl.col("amount") > 1000)
.group_by("region")
.agg(
mean_amount=pl.col("amount").mean(),
total=pl.col("amount").sum(),
)
)
La modalità lazy è dove Polars davvero stacca: pl.scan_parquet invece di pl.read_parquet, e l’engine pianifica l’intera computazione, spinge i filtri giù verso il reader del file, pota le colonne che non usi, ed esegue solo quando chiami .collect(). La vedremo nella lezione 35.
Quindi quale dovresti imparare?
Entrambi. Ma se hai tempo per uno solo per primo, è ancora pandas, ed ecco perché.
Scegli pandas quando:
- Il resto del tuo stack si aspetta un DataFrame. Scikit-learn, statsmodels, matplotlib, seaborn, plotly, ogni tutorial, ogni notebook Kaggle, ogni manuale di finanza quantitativa scritto prima del 2025: assumono che
dfsia unpandas.DataFrame. La fossa difensiva ecosistemica è il fattore decisivo la maggior parte dei giorni. - Stai facendo analisi interattiva in un notebook. La stampa più ricca di pandas, l’integrazione migliore con Jupyter, e la memoria muscolare di
df.head(),df.describe(),df["col"].value_counts()è dura da abbandonare. - I tuoi dati ci stanno comodamente su una macchina, che di solito significa sotto i 50 GB di dati in memoria. Pandas con il backend Arrow va bene in quella fascia.
- Lavori con un team che già conosce pandas. I costi di switching sono reali.
Scegli Polars quando:
- Stai costruendo una pipeline batch performance-critical che gira a un orario schedulato. Lo speedup di due-dieci volte si compone.
- I tuoi dati sono nella taglia scomoda: troppo grandi perché pandas sia comodo, troppo piccoli per giustificare Spark. Polars gestisce decine di milioni di righe su un laptop in un modo con cui pandas fa fatica.
- È un progetto nuovo senza vincoli di legacy o di conoscenza del team.
- Vuoi valutazione lazy, ottimizzazione delle query, e supporto out-of-core out of the box.
Il pattern “usa entrambi” è genuinamente comune nel 2026. Ingest e clean con Polars (perché è veloce e le operazioni sono pulite), poi .to_pandas() al confine in cui passi i dati a scikit-learn o statsmodels. Polars ha un to_pandas() zero-copy quando entrambi i lati usano Arrow, quindi il costo è essenzialmente zero.
import polars as pl
# Lavoro pesante in Polars
clean = (
pl.scan_parquet("raw/*.parquet")
.filter(pl.col("status") == "completed")
.group_by("user_id")
.agg(pl.col("amount").sum())
.collect()
)
# Passaggio a pandas per sklearn
df = clean.to_pandas(use_pyarrow_extension_array=True)
from sklearn.linear_model import LinearRegression
# ... addestra un modello su df ...
Cosa stiamo installando
Per il resto del Modulo 5 e del 6 ti serviranno:
uv add pandas pyarrow numpy
uv add polars # per la lezione 35 (e per provare cose accanto a pandas)
PyArrow è una hard dependency per il backend Arrow, quindi aggiungilo adesso anche se non sei sicuro che lo userai: metà delle moderne funzioni di lettura lo accettano e diverse feature di pandas avvertono o falliscono senza di lui.
Non ti serve Numba, Cython, Dask, o nessuno degli altri pacchetti “rendi pandas più veloce”. Toccheremo Dask nel Modulo 6 quando discuteremo l’out-of-core, ma per le prossime dieci lezioni è puro pandas, più il backend Arrow, più un pizzico di Polars per tenerti la prospettiva onesta.
Cosa copre questo modulo
Le prossime dieci lezioni:
- 26 Series e DataFrame: il modello dei dati, finalmente spiegato.
- 27 Lettura dei dati: CSV, Parquet, Excel, JSON, SQL, le insidie.
- 28 Selezione e filtering:
loc,iloc, maschere booleane,query. - 29 Aggiungere e trasformare colonne:
assign,apply, vettorizzazione. - 30 GroupBy: split-apply-combine, il cuore di pandas.
- 31 Join e merge: cosa si aspetta ogni sviluppatore SQL, e la trappola dell’indice.
- 32 Reshaping: pivot, melt, stack, unstack, la danza long/wide.
- 33 Dati mancanti: NaN,
pd.NA, la storia dei null in Arrow. - 34 Stringhe e categoriche: colonne di testo fatte bene.
- 35 Polars: stessi problemi, libreria diversa.
La lezione 26 è venerdì: il modello dei dati su cui si appoggia tutto quello che viene nelle nove lezioni successive. Saltala a tuo rischio; chi sorvola sulla distinzione Series/DataFrame/Index passa il resto della propria carriera con pandas in confusione.
Letture di approfondimento
- La pandas user guide: sorprendentemente leggibile, anche da copertina a copertina.
- What’s New in pandas 2.0: le release notes del backend Arrow.
- La Polars user guide: corta, moderna, ben scritta.
- La pagina del progetto Apache Arrow: per capire cosa fa il formato a colonne sotto a tutto.
- 10 Things I Hate About pandas di Wes McKinney (2017): il post che ha piantato il seme per pandas con backend Arrow.
Ci vediamo venerdì.