
Man mano che il panorama della data science diventa sempre più complesso, con nuove tecnologie che spuntano ogni giorno, scegliere la cassetta degli attrezzi giusta è fondamentale per il tuo progetto. Più il progetto è complesso, più dovrai essere cauto nella scelta degli strumenti da utilizzare, perché le tue decisioni incideranno in modo significativo sullo sviluppo e, in ultima analisi, sul successo del progetto.
Se stai lavorando a un progetto di data science, le scelte di design vanno ben oltre il dibattito Python vs R. Si tratta anche delle librerie da usare una volta scelti i linguaggi di programmazione su cui si baserà il progetto.
Nel caso di Python per la data science, pandas è lo strumento standard de facto per la manipolazione dei dati. I motivi per usare pandas sono numerosi e convincenti, ma ci sono anche limitazioni che possono creare colli di bottiglia importanti nei tuoi progetti. In particolare, è noto che pandas abbia prestazioni limitate quando si lavora con dataset di grandi dimensioni.
Per affrontare questi problemi, pandas ha rilasciato di recente la versione 2.0, che introduce revisioni importanti e miglioramenti di performance (dai un'occhiata a questo articolo per scoprire tutto quello che devi sapere su pandas 2.0).
Nel frattempo, nel mondo Python sono emerse nuove alternative che mettono in discussione il predominio di pandas. Una delle più popolari è polars, una libreria basata su Python e Rust per analisi dei dati più veloci.
In questo articolo analizzeremo le differenze tra pandas 2.0 e polars per la manipolazione dei dati. Partiremo da un'analisi delle strategie per migliorare le prestazioni di calcolo e concluderemo con una serie di test per confrontare le prestazioni dei due strumenti. Iniziamo!
Come scegliere tra pandas e polars
Non esiste una tecnologia migliore in assoluto per risolvere tutti i problemi e le situazioni che possono presentarsi nei tuoi workflow di data science. Prima di scegliere, vanno bilanciati diversi fattori. Ecco alcuni dei più rilevanti da considerare:
- Prestazioni di calcolo. In generale, più il progetto è grande e complesso, più dovresti considerare strumenti ad alte prestazioni per evitare colli di bottiglia computazionali.
- Compatibilità con lo stack tecnologico. Gli strumenti usati in un progetto di data science raramente lavorano in isolamento. Piuttosto, operano in combinazione con gli altri strumenti che compongono lo stack tecnologico. Prima di scegliere, valuta bene sinergie e compatibilità tra le tecnologie.
- Compatibilità del codice. Scegliere una nuova tecnologia significa anche considerare compatibilità ed efficienza del codice. Se adottare un nuovo strumento comporta riscrivere codice in progetti esistenti, dovresti includerlo nella valutazione.
- Popolarità. Infine, la popolarità di uno strumento è un indicatore di quante persone lo usano, fattore vantaggioso per assumere nuovi sviluppatori o risolvere dubbi di coding su piattaforme come Stack Overflow.
Come migliorare le prestazioni nella manipolazione dei dati?
In questa sezione vedremo le principali tecniche che possono aiutare ad aumentare le prestazioni nella manipolazione dei dati.
Ridurre le copie con il copy-on-write
Negli strumenti tradizionali per la manipolazione dei dati, ogni operazione porta alla creazione di una nuova copia dell'intero database. Questo comportamento può essere problematico per le risorse di memoria quando si lavora con dataset di grandi dimensioni.
Copy-on-write è la tecnica più comune per risolvere questo problema. In sostanza, il copy-on-write è una tecnica di gestione delle risorse che consente di implementare in modo efficiente un'operazione di "duplicazione" o "copia" su risorse modificabili. Ciò significa che, se un dataset viene duplicato ma non (interamente) modificato, non è necessario creare una nuova risorsa. Le risorse di memoria possono invece essere condivise tra la copia e l'originale.
Calcolo parallelo
Uno dei principali punti deboli di pandas è che è single-threaded, il che significa che non può sfruttare le tecniche di calcolo parallelo oggi comuni nella data science. Il calcolo parallelo si realizza principalmente con macchine multi-core o con il calcolo distribuito (cioè un gruppo di computer che lavorano insieme in un cluster).
Prendi il seguente esempio con la popolare funzione group by. Se vuoi calcolare l'età media dei giocatori di basket raggruppati per squadra, potresti usare il calcolo parallelo per assegnare il calcolo della media di ciascun gruppo a un core o a una macchina, invece di calcolarli uno per uno, aumentando così le prestazioni.

Ottimizzare l'import dei dati
Il punto di partenza dell'analisi dei dati è in genere la lettura dei dataset che vuoi studiare. Tuttavia, spesso questo passaggio rappresenta un collo di bottiglia nei progetti che coinvolgono dataset di grandi dimensioni. Ecco alcune tecniche che possono aiutare a migliorare le prestazioni in fase di lettura dei file:
- Suddivisione in chunk. Invece di leggere l'intero file, puoi suddividerlo in piccole porzioni, ovvero chunk. Questa tecnica consente un'importazione più rapida dei dati riducendo al contempo la memoria necessaria per archiviarli tutti contemporaneamente.
- Leggere solo le colonne necessarie. A volte sai già quali colonne di un dataset ti servono per l'analisi. Invece di leggere l'intero dataset, puoi applicare un filtro preliminare e leggere solo le colonne richieste.
- Downcasting dei tipi di dato. Strumenti come pandas hanno un comportamento predefinito nell'assegnare i tipi di dato alle colonne importate. Talvolta esistono altri tipi che richiedono meno memoria senza perdere informazioni. Il downcasting è il processo di modifica dei tipi di dato verso il tipo più piccolo in grado di gestirne i valori.
Valutazione lazy e pianificazione delle query
L'ordine in cui vengono eseguite le operazioni può influire sulle prestazioni. Spesso è possibile riordinare alcuni calcoli e ottenere la stessa risposta in modo più efficiente.
Ci sono due strategie per ottenere questo risultato: lazy evaluation e query planning. La prima si riferisce al processo di rimandare i calcoli finché non siano strettamente necessari. La seconda è il processo di trovare il modo più efficiente di eseguire più manipolazioni di dati dato un insieme di query diverse. Per farlo, la pianificazione delle query prevede in genere l'uso di un ottimizzatore di query.
Elaborazione out-of-core
Strumenti come pandas archiviano interi dataset in memoria, il che può essere problematico se lavori con dataset di grandi dimensioni che non entrano nella memoria del tuo computer o esegui operazioni particolarmente dispendiose in termini di memoria.
Qui entra in gioco l'elaborazione out-of-core. In parole semplici, l'elaborazione out-of-core fa riferimento a una memoria esterna (ad esempio, un disco esterno) che archivia dati che non potrebbero stare nella memoria centrale. L'elaborazione out-of-core consente di elaborare i dati archiviati esternamente in chunk, così da ottenere alla fine gli stessi risultati che otterresti eseguendo l'intero processo sul tuo computer.
Quali sono alcune alternative ad alte prestazioni a pandas?
Questo articolo si concentra sul confronto tra pandas 2.0 e polars, ma vale la pena menzionare anche altri strumenti che possono soddisfare le tue esigenze come alternative a pandas. Ecco alcuni tra i più promettenti:
- Koalas. Un'API pandas costruita sopra PySpark. Se usi Spark, dovresti considerare questo strumento.
- Vaex. Un'API pandas per il calcolo out-of-memory, ottima per analizzare grandi dati tabellari a miliardi di righe al secondo.
- Modin. Un'API pandas per la programmazione parallela, basata sui framework Dask o Ray per progetti big data. Se usi Dask o Ray, Modin è una grande risorsa.
- cuDF. Parte del progetto RAPIDS, cuDF è un'API simile a pandas per il calcolo su GPU che si basa su GPU NVIDIA o su altre componenti di RAPIDS per eseguire manipolazioni dei dati ad alta velocità.
Perchè scegliere polars?
Pandas è l'opzione di riferimento per chi usa Python, ma, come già spiegato, presenta diverse limitazioni importanti quando si tratta di gestire dataset di grandi dimensioni. La missione principale di polars è offrire una libreria di dataframe fulminea che affronti tutti i problemi di pandas.
Scritto in Rust (un potente linguaggio di programmazione che offre prestazioni C/C++ e consente di controllare completamente le parti critiche per le prestazioni in un motore di query), polars integra metodologie all'avanguardia per aumentare le prestazioni, progettate per:
- Migliorare il calcolo parallelo in modo da sfruttare tutti i core disponibili sulla tua macchina.
- Ottimizzare le query per ridurre lavoro/allocazioni di memoria non necessari usando lazy evaluation e query planning.
- Migliorare le prestazioni di archiviazione usando semantiche copy-on-write e Apache Arrow.
- Gestire dataset molto più grandi grazie alle capacità out-of-core tramite la sua API di streaming.
Ultimo ma non meno importante, polars ha una sintassi piuttosto simile a pandas e condivide gli stessi mattoni fondamentali, come Series e DataFrame. Questo ti semplificherà la vita se deciderai di passare a polars.
Come risponde pandas alla crescente concorrenza con pandas 2.0?
Per affrontare i problemi di prestazioni e controbilanciare la pressione dei concorrenti, pandas ha rilasciato da poco l'attesissima versione 2.0. In quanto major update, pandas 2.0 offre una serie di nuove funzionalità. Include anche deprecazioni applicate, con conseguenti modifiche all'API.
Il nuovo backend PyArrow è la scommessa principale del nuovo pandas per affrontare le sue limitazioni di performance. Gli utenti possono ora scegliere tra il tradizionale backend NumPy o il nuovissimo backend PyArrow. PyArrow è una libreria Python che fornisce un'interfaccia per gestire grandi dataset usando strutture di memoria Arrow.
pd.read_csv(my_file, engine='pyarrow')
Un'altra funzione importante è l'integrazione di diversi miglioramenti copy-on-write volti a migliorare le prestazioni risparmiando risorse di memoria.
Di conseguenza, molte operazioni di pandas ora includono un parametro predefinito “copy” che restituisce una copia lazy di oggetti base di pandas, come series e dataframe, invece di copie identiche memorizzate nella cache.
È ancora presto per sapere se le nuove capacità di pandas risolveranno i suoi problemi di performance. Anche se altri strumenti dovessero superarlo, ci saranno comunque buone ragioni per continuare a usare pandas: non dovrai riscrivere codice esistente o impararne di nuovo, perché probabilmente lo stai già usando.
pandas 2.0 vs polars: quadro di confronto
Ora che conosci la teoria, è il momento di sporcarsi le mani. Nelle sezioni seguenti eseguiremo una serie di test per confrontare le prestazioni di pandas 2.0 e polars. Il nostro benchmark sarà il tempo necessario per eseguire un'attività. Per farlo, useremo il modulo time, che offre un modo semplice per calcolare i tempi di esecuzione.
Oltre ai test sulle prestazioni, analizzeremo la compatibilità del codice di polars con pandas (cioè quanto codice devi cambiare se vuoi passare a polars?).
Il dataset
Testeremo le prestazioni di pandas 2.0 e polars su un dataset fittizio di vendite orarie di un'azienda con uffici in paesi diversi nel periodo 1980-2022. Per aggiungere complessità all'analisi, includeremo alcuni valori mancanti casuali.
In totale, il dataset comprende oltre 22 milioni di righe e più di 1,6 GB di memoria, abbastanza per mettere pandas sotto pressione. L'intero codice per i test di benchmark si trova in questo workbook DataLab.

Test di import
Iniziamo confrontando le prestazioni di pandas 2.0 e polars nell'import dei dati. Polars dichiara esplicitamente ottime prestazioni nell'import da CSV. È davvero così?
Eseguiremo un test per verificare quanto impiegano pandas e polars a leggere un sottoinsieme di colonne e righe. Ad esempio, supponiamo che tu voglia analizzare solo le vendite dell'ufficio in Francia. Con pandas, dovrai leggere tutte le righe e poi filtrare per rimuovere quelle non desiderate. Useremo il nuovissimo metodo .query() per farlo. Per provare il comportamento di pandas 2.0, importeremo il CSV sia con il tradizionale motore numpy che con il nuovo motore pyarrow.
Al contrario, polars fornisce il metodo filter() che, insieme a un certo set di condizioni, consente di leggere solo le righe di tuo interesse.
# pandas query
df_pd = pd.read_csv("./example.csv", engine="pyarrow")
df_pd = df_pd[['id', 'date', 'office', 'sales']]
df_pd = df_pd.query("office=='France'")
# polars filter
df_pl = pl.read_csv('example.csv').filter(
(pl.col('office') == 'France'))
df_pl.select(pl.col(['id', 'date', 'office', 'sales']))
Quando eseguiamo il test, polars risulta notevolmente più veloce di pandas, come mostrato nel grafico. Sorprendentemente, il motore pyarrow non ha dato risultati migliori del motore numpy standard.

In termini di compatibilità sintattica, polars ha chiaramente lo stesso "sapore" di pandas, con funzioni come pl.read_csv() che rispecchiano perfettamente pandas. Tuttavia, le due librerie funzionano in modo diverso sotto il cofano e questo porta inevitabilmente a differenze di sintassi, come dimostrano i metodi query() vs filter().
Test di group by
Le operazioni groupby si prestano bene alla parallelizzazione. Vediamo come si comportano pandas e polars in diverse operazioni aggregate per gruppi. In particolare, calcoleremo media e mediana delle vendite per ufficio e mese.
df_pd.groupby([df_pd.office, df_pd.date.dt.month])['sales'].agg('mean') # pandas groupby mean
df_pl.groupby([pl.col('office'), pl.col('date').dt.month()]).agg([pl.mean('sales')]) # polars groupby mean

df_pd.groupby([df_pd.office, df_pd.date.dt.month])['sales'].agg('median') # pandas groupby median
df_pl.groupby([pl.col('office'), pl.col('date').dt.month()]).agg([pl.median('sales')]) pandas groupby median

I risultati mostrano che, nei calcoli di group by e aggregazione, polars è più veloce di pandas. Anche qui, la sintassi di polars ricorda quella di pandas.
Test sulle statistiche mobili
Un'altra operazione adatta a testare le prestazioni di pandas e polars è il calcolo di statistiche mobili. Ottimizzare questo tipo di computazione richiede parecchio lavoro algoritmico. Vediamo come si comportano quando calcoliamo la media mobile giornaliera delle vendite.
# pandas rolling mean
df_pd['sales'].rolling(1440, min_periods=1).mean()
# polars rolling mean
df_pl['sales'].rolling_mean(1440, min_periods=1)
Anche stavolta vince polars. Nota la sottile differenza nella sintassi: polars include il metodo rolling_mean(), mentre pandas offre il metodo rolling() da combinare con altri metodi, come mean(), per ottenere lo stesso risultato.

Test di campionamento
Studiare l'intera popolazione di interesse per analizzare un fenomeno non è di solito possibile. Per questo il campionamento è una delle attività più comuni in statistica e data science. Ciò comporta il prelievo di campioni casuali usando tecniche di simulazione Monte Carlo, come bootstrap e permutazione. Tuttavia, questa operazione richiede anche molte copie di variabili, che possono essere impegnative se mancano le risorse di calcolo.
Vediamo come lavorano pandas e polars quando eseguiamo un bootstrap, ossia un ricampionamento con reinserimento. Stimeremo la media delle vendite in 10000 campioni composti da 1000 punti dati.
#pandas bootstrap
simu_weights = []
for i in range(10000):
bootstrap_sample = random.choices(df_pd['sales'], k=1000)
simu_weights.append(np.nanmean(bootstrap_sample))
#polars bootstrap
simu_weights = []
for i in range(10000):
bootstrap_sample = df_pl['sales'].sample(n=1000,with_replacement=True)
simu_weights.append(bootstrap_sample.mean())
Nel bootstrap sampling, polars è quasi 5 volte più veloce di pandas.
Quanto alla sintassi, mentre pandas si affida a numpy per le operazioni di campionamento, polars offre un comodo metodo integrato sample().

Manipolazioni composte
Per l'ultimo test, eseguiremo una serie di manipolazioni di dati collegate. Fa parte della quotidianità dei professionisti dei dati. Tuttavia, operazioni che coinvolgono molti passaggi sono facili da scrivere in modo computazionalmente subottimale.
Immagina che l'ufficio italiano dell'azienda fittizia stia valutando di assumere alcuni degli stagisti del 2022 dopo la fine del periodo di tirocinio. Il nostro obiettivo è analizzare quali sono stati gli stagisti che hanno realizzato le dieci operazioni di vendita più grandi nel 2022, così da usare queste informazioni per scegliere i candidati più adatti.
Per farlo, dobbiamo unire il nostro dataset con un secondo dataset, chiamato “italy_2022”, che contiene informazioni sulla persona che ha effettuato ciascuna transazione nel 2022. La colonna “id” è la colonna in comune tra i due dataset.

# pandas compound operations
df_pd.merge(italy_2022, on='id').query("responsibility =='Sales Intern'").sort_values('sales', ascending=False).head(10)[['name','surname','sales','sex']]
#polars compound manipulations
df_pl.join(italy_2022_pl, on="id").filter(pl.col('responsability') == 'Sales Intern').sort('sales',descending=True).head(10).select(pl.col(['name','surname','sales','sex']))

Come in tutti i test precedenti, polars batte pandas in termini di prestazioni. In questo test, l'operazione di join sembra essere l'ostacolo maggiore per pandas. Al contrario, polars è molto più efficiente, impiegando meno di due secondi per completare tutte le operazioni concatenate.
Tabella di confronto: pandas 2.0 vs polars
Abbiamo riassunto i test in una tabella per un confronto rapido:
|
Test |
Pandas 2.0 |
Polars |
Vincitore |
Somiglianza sintattica |
|
Test di import |
Legge tutte le righe e poi filtra quelle indesiderate usando il metodo .query() |
Legge direttamente solo le righe di interesse usando il metodo filter() |
Polars (prestazioni migliori) |
Simile, ma con differenze dovute all'implementazione sottostante (.query() vs filter()) |
|
Test di Group By |
Usa .groupby() per operazioni di aggregazione come media e mediana delle vendite per ufficio e mese |
Come pandas, ma con prestazioni migliori |
Polars (prestazioni migliori) |
Simile |
|
Test statistiche mobili |
Usa il metodo rolling() combinato con altri metodi, come mean(), per i calcoli della media mobile |
Usa il metodo rolling_mean() per i calcoli della media mobile |
Polars (prestazioni migliori) |
Simile, ma con leggere differenze (.rolling().mean() vs rolling_mean()) |
|
Test di campionamento |
Usa numpy per le operazioni di bootstrap sampling |
Usa il metodo integrato sample() per le operazioni di bootstrap sampling |
Polars (quasi 5 volte più veloce) |
Diversa: pandas si affida a numpy mentre polars ha metodi integrati |
|
Test di manipolazioni composte |
Esegue un'operazione di join con un altro dataset e poi ordina e seleziona i dati |
Esegue le stesse attività ma in modo più efficiente |
Polars (significativamente più veloce) |
Simile, ma con leggere differenze (merge().query().sort_values().head() vs join().filter().sort().head().select()) |
Fai un passo in più
Congratulazioni per essere arrivato alla fine di questo tutorial. In base ai test, polars offre prestazioni nettamente migliori di pandas 2.0 in quasi tutte le prove. Sebbene questo rappresenti una vera minaccia al suo predominio, pandas ha ancora il vantaggio di essere l'opzione di riferimento per la manipolazione dei dati in Python, godendo quindi di tutti i benefici di una community più ampia.
Se lavori con dataset grandi, aumentare le prestazioni è imprescindibile. DataCamp ti copre le spalle. Ecco una lista di corsi che possono aiutarti a portare le tue performance a un livello superiore:
Sono una data analyst freelance e collaboro con aziende e organizzazioni di tutto il mondo in progetti di data science. Sono anche un'insegnante di data science con oltre 2 anni di esperienza. Scrivo regolarmente articoli su temi legati alla data science in inglese e spagnolo, alcuni dei quali sono stati pubblicati su siti affermati come DataCamp, Towards Data Science e Analytics Vidhya. Come data scientist con un background in scienze politiche e diritto, il mio obiettivo è lavorare all'intersezione tra politiche pubbliche, diritto e tecnologia, sfruttando la forza delle idee per promuovere soluzioni e narrazioni innovative che ci aiutino ad affrontare le sfide urgenti, in primis la crisi climatica. Mi considero autodidatta, una persona in continuo apprendimento e una convinta sostenitrice dell'approccio multidisciplinare. Non è mai troppo tardi per imparare cose nuove.


