Polars - Foglio di aiuto della libreria Fast DataFrame
Polars è una libreria DataFrame ad alte prestazioni scritta in Rust con binding per Python, R e Node. È multi-thread per impostazione predefinita, costruito sulla memoria colonnare Apache Arrow e offre un”API lazy con un ottimizzatore di query che riordina e elimina il lavoro prima dell”esecuzione. Su set di dati grandi è tipicamente molte volte più veloce di pandas e utilizza meno memoria, mentre la sua API di espressione si compone più chiaramente. È diventata la raccomandazione predefinita per il nuovo lavoro di dati nel 2026.
Installazione
| Metodo | Comando |
|---|
| pip | pip install polars |
| uv | uv add polars |
| Con extra | pip install "polars[all]" (excel, database, plotting) |
| Verifica | python -c "import polars as pl; print(pl.__version__)" |
Lettura e scrittura
| Operazione | Codice |
|---|
| CSV | pl.read_csv("data.csv") |
| Parquet | pl.read_parquet("data.parquet") |
| JSON | pl.read_json("data.json") |
| Database | pl.read_database(query, connection) |
| Lazy CSV | pl.scan_csv("data.csv") (rinviato) |
| Lazy Parquet | pl.scan_parquet("*.parquet") |
| Write | df.write_parquet("out.parquet") |
Eager vs Lazy (l’idea chiave)
import polars as pl
# Eager: esegue immediatamente
df = pl.read_csv("sales.csv")
result = df.filter(pl.col("amount") > 100).group_by("region").agg(pl.col("amount").sum())
# Lazy: costruisce un piano, ottimizza, quindi esegui su .collect()
result = (
pl.scan_csv("sales.csv")
.filter(pl.col("amount") > 100)
.group_by("region")
.agg(pl.col("amount").sum())
.collect()
)
La modalità lazy consente all”ottimizzatore di spingere i filtri verso il basso fino alla scansione e leggere solo le colonne necessarie — spesso un grande speedup su file grandi. Preferisci scan_* + .collect() per i carichi di lavoro reali.
Espressioni (l’API principale)
| Espressione | Fa |
|---|
pl.col("x") | Riferimento a una colonna |
pl.col("x").sum() | Aggrega |
pl.col("x").alias("y") | Rinomina output |
pl.col("*") | Tutte le colonne |
pl.lit(5) | Valore letterale |
pl.when(cond).then(a).otherwise(b) | Condizionale |
Selezione e filtro
| Compito | Codice |
|---|
| Seleziona colonne | df.select("a", "b") |
| Colonna calcolata | df.with_columns((pl.col("a") * 2).alias("a2")) |
| Filtra righe | df.filter(pl.col("a") > 10) |
| Condizioni multiple | df.filter((pl.col("a") > 10) & (pl.col("b") == "x")) |
| Head/tail | df.head(10), df.tail(10) |
| Ordina | df.sort("a", descending=True) |
| Unico | df.unique(subset=["a"]) |
Aggregazione e raggruppamento
(df.group_by("region")
.agg(
pl.col("amount").sum().alias("total"),
pl.col("amount").mean().alias("avg"),
pl.col("order_id").n_unique().alias("orders"),
))
| Aggregazione | Espressione |
|---|
| Sum/mean/min/max | .sum(), .mean(), .min(), .max() |
| Count | .count(), .n_unique() |
| First/last | .first(), .last() |
| Quantile | .quantile(0.95) |
| List collect | .implode() |
Join
| Tipo | Codice |
|---|
| Inner | a.join(b, on="id") |
| Left | a.join(b, on="id", how="left") |
| Outer | a.join(b, on="id", how="full") |
| Anti | a.join(b, on="id", how="anti") |
| Semi | a.join(b, on="id", how="semi") |
| As-of (time) | a.join_asof(b, on="ts") |
Stringhe, date, elenchi
| Namespace | Esempio |
|---|
.str | pl.col("s").str.to_uppercase(), .str.contains("x") |
.dt | pl.col("t").dt.year(), .dt.truncate("1h") |
.list | pl.col("l").list.len(), .list.first() |
.cast | pl.col("a").cast(pl.Int64) |
Interop
| Obiettivo | Codice |
|---|
| pandas | df.to_pandas() / pl.from_pandas(pdf) |
| Arrow | df.to_arrow() |
| NumPy | df.to_numpy() |
| DuckDB | Interroga direttamente frame Polars da DuckDB |
Polars vs pandas
| Aspetto | Polars | pandas |
|---|
| Engine | Rust, multi-thread | Python/C, principalmente single-thread |
| Memory | Arrow colonnare | Supportato da NumPy |
| Lazy optimizer | Sì | No |
| API | Expression-based, componibile | Index-centrica |
| Ecosystem | Crescita rapida | Vasto, maturo |
Per l”analisi SQL-first su file, abbinato con DuckDB; pandas rimane prezioso per la vastità dell”ecosistema.
Risorse