Polars, qui es-tu ? D’où viens-tu ?
Vous avez peut-être déjà entendu parler de Polars : il s’agit d’un package permettant de traiter des données bien plus rapidement que Pandas.
Polars est défini par ses créateurs comme :
« Polars est une bibliothèque de DataFrames ultra-rapide, implémentée en Rust et utilisant Apache Arrow Columnar Format comme modèle de mémoire. »
Ses principales caractéristiques sont :
- Multi-threading : exploitation du parallélisme des processeurs pour accélérer les traitements.
- SIMD (Single Instruction Multiple Data) : exécutions d’instructions vectorisées pour traiter les données plus rapidement.
- Optimisation des requêtes : Polars analyse et optimise automatiquement le plan d’exécution.
- Streaming hybride (ensembles de données plus grands que la RAM) : permet de traiter des données volumineuses sans tout charger en mémoire d’un seul coup.
Polars est né d’un constat : la manipulation de données avec Pandas révèle certaines limites (performances, gestion de la mémoire, etc.), alors pourquoi ne pas tirer parti d’autres technologies pour y remédier ? Rust, un langage rapide et sûr, associé au format colonne Apache Arrow, a donc donné naissance à Polars.
Mais plutôt que de lister forces et faiblesses, rentrons directement dans le vif du sujet : manipuler Polars !
1. Installation de Polars
Polars a très peu de dépendances, ce qui rend son installation très simple. Il vous suffit de créer un environnement virtuel (ou utiliser un existant) et de lancer la commande :
pip install polars
Cette commande installera Polars et tout ce dont il a besoin pour fonctionner (essentiellement pyarrow
et quelques dépendances).
Astuce : Si vous utilisez conda, vous pouvez également faire :
conda install -c conda-forge polars
2. Découverte de l’API Polars
2.1 Import et création d’un DataFrame
Tout d’abord, importons Polars :
import polars as pl
Pour créer un DataFrame à partir de données Python (listes, dictionnaires, etc.) :
df = pl.DataFrame({
"nom": ["Alice", "Bob", "Charlie"],
"âge": [25, 30, 35],
"ville": ["Paris", "Lyon", "Marseille"]
})
print(df)
Vous obtiendrez quelque chose comme :
shape: (3, 3)
┌─────────┬─────┬────────────┐
│ nom ┆ âge ┆ ville │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ str │
╞═════════╪═════╪════════════╡
│ Alice ┆ 25 ┆ Paris │
│ Bob ┆ 30 ┆ Lyon │
│ Charlie ┆ 35 ┆ Marseille │
└─────────┴─────┴────────────┘
Le DataFrame est alors prêt à être manipulé. Vous constaterez que Polars affiche le schéma (shape, types de colonnes) et un aperçu des données.
2.2 Lecture de fichiers CSV et Parquet
Comme Pandas, Polars sait lire plusieurs formats de fichiers. Les plus courants sont le CSV et le Parquet :
# Lecture d'un fichier CSV
df_csv = pl.read_csv("chemin/vers/fichier.csv")
# Lecture d'un fichier Parquet
df_parquet = pl.read_parquet("chemin/vers/fichier.parquet")
Par défaut, Polars détecte les types de colonnes et essaye d’optimiser leur chargement.
3. Manipulations de base
3.1 Sélection de colonnes et filtrage
Admettons que vous ayez un DataFrame de ventes df_ventes
, avec des colonnes comme produit
, quantité
et prix_unitaire
:
df_ventes = pl.DataFrame({
"produit": ["A", "B", "A", "C", "B"],
"quantité": [10, 5, 3, 8, 2],
"prix_unitaire": [2.50, 4.00, 2.50, 6.00, 4.00]
})
# Sélection de colonnes et ajout d'une colonne 'total'
df_sel = df_ventes.select([
pl.col("produit"),
pl.col("quantité"),
(pl.col("quantité") * pl.col("prix_unitaire")).alias("total")
])
print(df_sel)
On utilise la méthode select
et les expressions Polars (pl.col(...)
) pour manipuler les colonnes. Polars, contrairement à Pandas, recommande un style fonctionnel pour réaliser des opérations (ex. select
, with_columns
, etc.).
3.2 GroupBy et agrégations
Le group_by et les agrégations sont plus rapides et plus intuitifs grâce à la syntaxe basée sur les expressions. Par exemple, pour connaître le total des ventes par produit :
df_group = df_ventes.group_by("produit").agg([
pl.col("quantité").sum().alias("sum_qte"),
(pl.col("quantité") * pl.col("prix_unitaire")).sum().alias("sum_total")
])
print(df_group)
Vous obtiendrez un DataFrame agrégé, avec une ligne par produit et les sommes désirées.
4. Les grands principes de Polars
4.1 Le format colonne (Apache Arrow)
Polars stocke les données en colonne, via le format Apache Arrow.
- Avantage 1 : Polars peut exécuter des opérations vectorisées beaucoup plus rapidement.
- Avantage 2 : La manipulation des données en colonne (et non en ligne) réduit les coûts de cache et optimise les requêtes complexes.
4.2 Le moteur Rust ultra-rapide
Rust est réputé pour sa vitesse d’exécution et sa sécurité mémoire. En l’utilisant comme colonne vertébrale, Polars parvient à battre Pandas sur de nombreux benchmarks (pour le chargement, le groupby, la jointure, etc.).
4.3 Le multi-threading et SIMD
Polars tire parti du multi-threading (exécuter plusieurs tâches en parallèle) et des instructions vectorielles (SIMD) pour accélérer considérablement les opérations sur de larges volumes de données.
4.4 La « Lazy API »
Une caractéristique-clé : Polars Lazy. Elle permet de différer l’exécution d’une suite d’opérations pour construire un plan global optimisé (similaire à Spark ou dask).
- Vous enchaînez les transformations de façon déclarative (e.g.
df.filter(...).select(...).groupby(...)
), - Polars génère ensuite un plan d’exécution unique et l’optimise avant de lancer le calcul.
Exemple :
# Passage en Lazy mode
df_lazy = df_ventes.lazy()
# Définition de transformations successives, mais non exécutées immédiatement
df_lazy = df_lazy.filter(pl.col("quantité") > 3)
df_lazy = df_lazy.group_by("produit").agg([
pl.col("quantité").sum().alias("sum_qte")
])
# Seule cette ligne déclenche l'exécution et renvoie un DataFrame "classique"
df_result = df_lazy.collect()
print(df_result)
Cette approche est particulièrement utile quand vous traitez de gros jeux de données : Polars peut optimiser chaque étape (pushdown des filtres, exécution partielle, etc.).
5. Streaming hybride : gérer des données plus grosses que la RAM
Un atout de Polars réside dans sa capacité à lire les fichiers en streaming. Cela permet de traiter des données plus grandes que la mémoire de votre machine, en les lisant et en les traitant par blocs :
df_stream = pl.scan_csv(
"chemin/vers/gros_fichier.csv",
has_header=True,
ignore_errors=True
)
# On peut alors appliquer des transformations Lazy
df_stream = df_stream.select([
pl.col("col1"),
pl.col("col2")
]).filter(pl.col("col3") == "valeur")
# collect() déclenche l'exécution en streaming, avec un usage mémoire constant
result = df_stream.collect()
Ici, scan_csv
au lieu de read_csv
permet d’indiquer à Polars d’adopter un mode lazy et streaming si possible. Les colonnes non utilisées peuvent ainsi être ignorées dès la phase de lecture, et les étapes de filtrage ou d’agrégation sont traitées en pipeline.
6. Comparaison rapide Polars vs Pandas
- Performance : Polars est souvent 2 à 5 fois plus rapide que Pandas sur des opérations classiques (join, group_by, etc.), et jusqu’à des ordres de grandeur supérieurs sur de très gros volumes.
- Modèle de données : Pandas utilise un modèle basé sur NumPy (souvent ligne par ligne), Polars utilise Apache Arrow (colonne). Attention, pandas est en train de modifier cette approche en utilisant aussi Arrow.
- Syntaxe : Pandas met l’accent sur la manipulation DataFrame impérative (df[« col »] = …), Polars incite à un style d’expressions (df.select([pl.col(« … »)])) ou lazy.
- Maturité de l’écosystème : Pandas demeure la référence historique, avec un nombre immense de ressources et de projets. Polars est plus récent, mais progresse très vite et bénéficie de l’essor de la communauté Rust/Arrow.
7. Conseils et bonnes pratiques
- Découper le traitement : exploitez la Lazy API pour chaîner les opérations et laisser Polars optimiser.
- Utiliser Arrow / Parquet : lire et écrire des fichiers Parquet ou Arrow permet de conserver le schéma des données et évite des conversions coûteuses.
- Surveiller la mémoire : même si Polars est plus efficace, un DataFrame peut encore exploser la RAM si vous traitez 1 To de données. Le streaming et la lazy execution permettent d’atténuer ce risque.
- Rester vigilant sur les conversions : si vous passez souvent de Pandas à Polars et inversement, essayez d’optimiser les transferts (Arrow / zero-copy) pour éviter les copies inutiles.
- Profiler vos scripts : sur un gros pipeline de data, testez différentes stratégies (lazy vs non-lazy, partitionnement des fichiers, etc.) pour trouver la configuration la plus efficace.
8. Conclusion
Polars s’impose comme une solution ultra-rapide et ergonomique pour la manipulation de données en Python. Soutenu par un moteur Rust performant et l’implémentation du format colonne Apache Arrow, Polars excelle particulièrement dans :
- La vitesse de chargement et de transformation,
- La gestion de gros volumes de données (notamment en streaming),
- L’optimisation automatique via la Lazy API,
- La simplicité de syntaxe, orientée vers des expressions puissantes et lisibles.
Si vous êtes familier avec Pandas, vous trouverez vite vos marques dans Polars. Et si vous travaillez sur de la data volumineuse, Polars peut vous faire gagner un temps précieux tout en réduisant votre consommation de ressources. Il ne vous reste qu’à tester et à observer la différence dans vos projets !
Bonnes analyses avec Polars !
Partager cet article