Polars ist eine moderne DataFrame-Bibliothek für Python, die auf Apache Arrow basiert. Sie wurde mit Fokus auf Performance, Speichereffizienz und Parallelisierung entwickelt. Während Pandas nach wie vor der Standard für Datenverarbeitung in Python ist, stößt es bei sehr großen Datenmengen oder komplexen Pipelines zunehmend an Grenzen. Genau hier kann Polars helfen, da es extrem schnell ist und gut mit großen Datenmengen umgehen kann. Unter der Haube nutzt Polars die Sprache Rust und führt viele Operationen lazy (also verzögert) und parallel aus.
Erste Schritte
Polars lässt sich einfach über pip installieren und danach in jedem Python file einfach als pl importieren
pip install polars
Um einen einfachen Dataframe zu erstellen, geht man in Polars sehr ähnlich vor wie in pandas:
import polars as pl
df = pl.DataFrame({
"name": ["Alice", "Bob", "Charlie"],
"age": [25, 30, 35],
"city": ["Berlin", "Hamburg", "Berlin"]
})
df
Eager vs. Lazy API
In Polars gibt es zwei Modi der Verarbeitung:
- Eager: Operationen werden sofort ausgeführt (ähnlich Pandas)
- Lazy: Operationen werden gesammelt und später optimiert ausgeführt (ähnlich Spark)
Die verzögerte Ausführung im Lazy Modus hat dabei den Vorteil, das Polars mehrere Verarbeitungsschritte optimiert ausführen kann, bspw. in dem Filter zusammengezogen werden, unnötige Spalten verworfen werden oder Berechnungen neu angeordnet werden. Um den Lazy Modus zu aktivieren verwendet man folgenden Befehl:
df_lazy = df.lazy()
Verschiedene Operationen kann man in Polars einfach aneinander ketten. Am Ende wird mit .collect() die komplette Operation ausgeführt:
result = (
df.lazy()
.filter(pl.col("age") > 25)
.select(["name", "age"])
.collect()
)
Auswahl von Spalten
Bei polars werden die meisten Operationen mit Methoden ausgeführt (im Gegensatz zu pandas, wo mit der Indizierung gearbeitet wird).
Um nur bestimmte Spalten auszuwählen, verwendet man die select-Methode. Ebenso wie bei pandas, wird der ursprüngliche Dataframe dadurch nicht verändert, sondern nur eine temporäre Sicht dargestellt:
df.select(["name", "age"])
Um Spalten zu verändern, kann man Berechnungen direkt in der Methode ausführen. Um beispielsweise die Spalte „age“ mit 2 zu multiplizieren kann man folgenden Code verwenden:
df.select(pl.col("age") * 2)<br>Und wie bereits oben beschrieben, kann man auch mehrere Transformationen gleichzeitig ausführen:
df.select([
pl.col("name"),
(pl.col("age") + 1).alias("age_next_year")
])
Filtern von Zeilen
Das Filtern von Zeilen erfolgt mithilfe der filter-Methode. Einzelne Filterbedingungen können beispielsweise mit „&“ verknüpft werden.
# Einfacher Filter
df.filter(pl.col("age") > 25)
# Kombinierte Bedingungen
df.filter(
(pl.col("age") > 25) & (pl.col("city") == "Berlin")
)
Neue Spalten erzeugen
In Polars werden neue Spalten mithilfe des Befehls „with_columns“ erzeugt. Dazu wird eine Berechnung für die neue Spalte angegeben und anschließend mit der alias-Methode ein neuer Name vergeben.
df.with_columns(
(pl.col("age") * 12).alias("age_in_months")
)
Das geht auch für mehrere Spalten auf einmal:
df.with_columns([
(pl.col("age") + 1).alias("age_plus_one"),
pl.col("name").str.to_uppercase().alias("name_upper"),
pl.Series("random_values", [5, 20, 189])
])
GroupBy und Aggregationen
Groupby funktioniert fast genauso wie in pandas:
df.group_by("city").agg(
pl.col("age").mean().alias("avg_age")
)
Mehrere Aggregationen:
df.group_by("city").agg([
pl.col("age").mean().alias("avg_age"),
pl.len().alias("n")
])
Sortieren
Sortieren geht fast genauso wie in pandas.
df.sort("age", descending=True)
Mehrere Spalten:
df.sort(["city", "age"])
Arbeiten mit Strings
Auch das Arbeiten mit Strings funktioniert sehr simpel:
df.with_columns(
pl.col("city").str.contains("er").alias("has_er")
)
df.with_columns(
pl.col("name").str.len_chars().alias("name_length")
)
Fehlende Werte
Fehlender Wert auffüllen oder entfernen geht mit fill_null oder drop_nulls:
df.fill_null(0)
df.drop_nulls()
Das kann natürlich auch gezielt auf einzelne Spalten angewendet werden:
df.with_columns(
pl.col("age").fill_null(pl.col("age").mean())
)
Einlesen großer Datenmengen
Polars ist besonders stark beim Lesen großer Dateien. Einfache csv Dateien können dabei mit read_csv eingelesen werden:
pl.read_csv("data.csv")
Um bei sehr großen Datenmengen lazy einzulesen und zu Streamen verwendet man scan_csv:
pl.scan_csv("data.csv") \
.filter(pl.col("value") > 0) \
.groupby("category") \
.agg(pl.sum("value")) \
.collect()