Hub documentation
Optimisations
Optimisations
Nous avons brièvement évoqué la différence entre l'évaluation paresseuse (lazy) et l'évaluation immédiate (eager). Sur cette page, nous montrons comment l'API paresseuse peut être utilisée pour obtenir des gains de performance considérables.
Lazy vs Eager
Polars prend en charge deux modes de fonctionnement : lazy et eager. Dans l'API eager, la requête est exécutée immédiatement, tandis que dans l'API lazy, la requête n'est évaluée que lorsqu'elle est « nécessaire ». Différer l'exécution au dernier moment peut offrir des avantages de performance significatifs, ce qui explique pourquoi l'API lazy est préférée dans la plupart des cas non interactifs.
Exemple
Nous utiliserons l’exemple de la page précédente pour montrer les avantages en termes de performance de l’API paresseuse. Le code ci-dessous calcule le nombre de téléversements depuis archive.org.
Eager
import polars as pl
import datetime
df = pl.read_csv("hf://datasets/commoncrawl/statistics/tlds.csv", try_parse_dates=True)
df = df.select("suffix", "crawl", "date", "tld", "pages", "domains")
df = df.filter(
(pl.col("date") >= datetime.date(2020, 1, 1)) |
pl.col("crawl").str.contains("CC")
)
df = df.with_columns(
(pl.col("pages") / pl.col("domains")).alias("pages_per_domain")
)
df = df.group_by("tld", "date").agg(
pl.col("pages").sum(),
pl.col("domains").sum(),
)
df = df.group_by("tld").agg(
pl.col("date").unique().count().alias("number_of_scrapes"),
pl.col("domains").mean().alias("avg_number_of_domains"),
pl.col("pages").sort_by("date").pct_change().mean().alias("avg_page_growth_rate"),
).sort("avg_number_of_domains", descending=True).head(10)Lazy
import polars as pl
import datetime
lf = (
pl.scan_csv("hf://datasets/commoncrawl/statistics/tlds.csv", try_parse_dates=True)
.filter(
(pl.col("date") >= datetime.date(2020, 1, 1)) |
pl.col("crawl").str.contains("CC")
).with_columns(
(pl.col("pages") / pl.col("domains")).alias("pages_per_domain")
).group_by("tld", "date").agg(
pl.col("pages").sum(),
pl.col("domains").sum(),
).group_by("tld").agg(
pl.col("date").unique().count().alias("number_of_scrapes"),
pl.col("domains").mean().alias("avg_number_of_domains"),
pl.col("pages").sort_by("date").pct_change().mean().alias("avg_page_growth_rate"),
).sort("avg_number_of_domains", descending=True).head(10)
)
df = lf.collect()Délais
L’exécution des deux requêtes donne les temps d’exécution suivants sur un ordinateur portable standard avec une connexion Internet domestique :
- Eager :
1.96secondes - Lazy :
410millisecondes
La requête paresseuse est environ 5 fois plus rapide que la requête zélée. La raison en est l’optimiseur de requêtes : si nous retardons la collecte de notre jeu de données jusqu’à la fin, Polars pourra raisonner sur les colonnes et les lignes nécessaires et appliquer les filtres le plus tôt possible lors de la lecture des données. Pour les formats de fichiers tels que Parquet qui contiennent des métadonnées (par exemple, min, max dans un certain groupe de lignes), la différence peut même être plus importante, car Polars peut ignorer des groupes de lignes entiers sur la base des filtres et des métadonnées sans envoyer les données sur le réseau.