Polars adalah library DataFrame Python yang ditulis dalam Rust dengan backend Apache Arrow, menawarkan kecepatan 5-30x lebih cepat dibanding Pandas untuk operasi grup, join, dan agregasi pada dataset menengah hingga besar. Sejak rilis stabil Polars 1.0 pada Agustus 2024 dan versi 1.x di sepanjang 2025-2026, library ini sudah jadi alternatif serius untuk Pandas, terutama ketika dataset Anda lebih besar dari beberapa ratus megabyte atau saat throughput pipeline ETL menjadi bottleneck. Panduan ini membandingkan Polars vs Pandas dari sisi API, performa, ekosistem, plus langkah konkret untuk migrasi.
Polars 1.x menggunakan engine Rust multi-threaded dengan eksekusi lazy (LazyFrame) yang memungkinkan query optimizer melakukan predicate pushdown dan projection pruning secara otomatis.
Pada benchmark TPC-H scale factor 10 (sekitar 10 GB), Polars umumnya 5-15x lebih cepat dari Pandas 2.x untuk query yang sama, dan dapat memproses data lebih besar dari RAM lewat streaming engine.
API Polars berbasis expression (pl.col("x").mean()) yang lebih konsisten dibanding Pandas, tetapi membutuhkan perubahan pola pikir dari df["x"].mean() ke chaining expression.
Polars 1.x mendukung GPU engine berbasis NVIDIA cuDF, integrasi DuckDB, dan zero-copy interop dengan PyArrow serta NumPy.
Migrasi tidak perlu all-or-nothing. Fungsi df.to_pandas() dan pl.from_pandas(df) memungkinkan konversi murah karena keduanya berbagi format Arrow.
Pandas masih unggul untuk ekosistem (scikit-learn, statsmodels, plotting library) dan kompatibilitas dengan kode legacy serta tutorial yang ada.
Apa itu Polars dan kenapa cepat?
Polars adalah library DataFrame open source yang dibuat oleh Ritchie Vink. Berbeda dengan Pandas yang ditulis sebagian besar dalam C dan Python di atas NumPy, Polars ditulis dalam Rust dan menggunakan format kolumnar Apache Arrow sebagai representasi memori internal. Tiga keputusan arsitektur ini menjelaskan keunggulan performanya. Kompiler Rust memberikan kontrol memori tanpa garbage collector, format Arrow memungkinkan akses vektor dan operasi SIMD efisien, dan semua operasi mendukung paralelisasi multi-core secara default.
Honestly, saya pertama kali memakai Polars secara serius pada awal 2024 untuk pipeline ETL log server yang sebelumnya butuh delapan menit dengan Pandas. Pipeline yang sama selesai dalam 22 detik tanpa mengubah logika bisnis. Kuncinya bukan sekadar Rust, tapi kombinasi query optimizer bawaan: ketika Anda menulis lf.filter(...).select(...).groupby(...), Polars menganalisis seluruh rangkaian dan dapat memindahkan filter ke awal pembacaan file Parquet (predicate pushdown), hanya membaca kolom yang dipakai (projection pruning), serta menggabungkan operasi yang bisa di-fuse menjadi satu lintasan data.
Pandas, sebaliknya, mengeksekusi setiap operasi secara eager. Setiap baris kode menghasilkan DataFrame baru di memori, tanpa pengetahuan tentang operasi berikutnya. Untuk dataset kecil (di bawah 100 MB) perbedaan ini tidak terasa, tapi pada data berukuran gigabyte selisihnya menjadi orde magnitude.
Tabel perbandingan Polars vs Pandas
Tabel berikut merangkum dimensi yang paling sering ditanyakan saat tim memutuskan apakah akan migrasi. Angka performa adalah rata-rata dari TPC-H benchmark dan pengukuran internal saya pada workstation 16-core/64 GB RAM dengan dataset 5-10 GB Parquet.
Dimensi
Polars 1.x
Pandas 2.x / 3.0
Bahasa implementasi
Rust
C, Cython, Python (sebagian PyArrow opsional)
Backend memori
Apache Arrow (default)
NumPy (default), PyArrow (opsional)
Eksekusi
Eager dan Lazy (LazyFrame)
Eager saja
Multi-threading
Otomatis pada hampir semua operasi
Mostly single-thread; perlu Dask/Modin untuk paralel
Instalasi Polars sederhana dan tidak membutuhkan kompiler Rust di sisi pengguna karena distribusi dilakukan sebagai wheel pra-kompilasi. Untuk lingkungan produksi 2026, gunakan Python 3.11 atau 3.12. Polars sudah mendukung Python 3.13 tetapi beberapa library pelengkap belum stabil di sana.
# Instalasi dasar
pip install "polars>=1.20"
# Dengan dukungan ekstra (PyArrow, NumPy, pandas, Excel, koneksi database)
pip install "polars[all]>=1.20"
# Khusus untuk eksperimen GPU (membutuhkan NVIDIA GPU + CUDA 12)
pip install "polars[gpu]>=1.20" cudf-cu12
# Verifikasi versi dan fitur yang aktif
python -c "import polars as pl; print(pl.__version__); pl.show_versions()"
Polars memiliki dua varian build: polars (default) dan polars-lts-cpu. Varian LTS dibutuhkan jika CPU server Anda tidak mendukung AVX2, misalnya di sebagian VM cloud lama atau perangkat ARM tanpa NEON yang konfigurasinya tidak standar. Periksa dengan cat /proc/cpuinfo | grep avx2 pada Linux. Jika hasilnya kosong, gunakan pip install polars-lts-cpu sebagai gantinya.
DataFrame vs LazyFrame: kapan pakai yang mana
Polars menawarkan dua mode eksekusi: DataFrame (eager, mirip Pandas, setiap operasi langsung dieksekusi) dan LazyFrame (operasi disimpan sebagai logical plan, dieksekusi hanya saat .collect() dipanggil). Memilih yang tepat adalah faktor performa terbesar setelah Anda memutuskan pindah ke Polars.
So, kapan pakai yang mana? Gunakan DataFrame ketika Anda eksplorasi interaktif di Jupyter, ketika dataset kecil (di bawah 100 MB), atau saat Anda perlu hasil setiap operasi untuk diperiksa. Gunakan LazyFrame untuk pipeline produksi, ETL batch, dan kapanpun Anda membaca file Parquet/CSV yang lebih besar dari 500 MB. Query optimizer akan menghemat I/O dan memori secara dramatis.
import polars as pl
# Mode eager: baca seluruh file, lalu filter
df = pl.read_csv("transaksi.csv")
result = df.filter(pl.col("status") == "PAID").select(["id", "total"])
# Mode lazy: query optimizer melakukan predicate pushdown
# Filter dipindahkan ke level CSV reader sehingga baris non-PAID
# tidak pernah dimuat ke memori
lf = pl.scan_csv("transaksi.csv")
result = (
lf.filter(pl.col("status") == "PAID")
.select(["id", "total"])
.collect() # eksekusi terjadi di sini
)
# Periksa rencana eksekusi sebelum collect()
print(lf.explain(optimized=True))
Perhatikan penggunaan pl.scan_csv() dan pl.scan_parquet() untuk membuka file sebagai LazyFrame, berbeda dengan pl.read_csv() yang langsung memuat. Pada Parquet, perbedaan ini bisa berarti membaca 50 MB metadata vs membaca 5 GB data. Saya pernah melihat pipeline yang dipercepat 40x hanya dengan mengganti read_parquet menjadi scan_parquet, dan saya hampir tidak percaya sampai melihat profilnya sendiri.
API Expression Polars vs API Pandas
Perbedaan API terbesar adalah pendekatan expression. Di Pandas, Anda memanipulasi DataFrame langsung dengan indexer dan accessor: df["x"].mean(), df.loc[df["age"] > 18], df.groupby("kota")["pendapatan"].sum(). Di Polars, Anda menulis ekspresi yang merupakan deskripsi komputasi, lalu diterapkan dalam konteks (select, filter, group_by, with_columns).
Setelah membiasakan diri, API expression terasa lebih konsisten karena setiap ekspresi adalah objek yang sama, dapat di-compose, di-reuse, dan diuji unit. Anda tidak akan menemukan kasus "ini di Pandas pakai .loc, ini pakai .iloc, ini pakai .query()" yang sering membingungkan pemula. Untuk pembaca yang sudah membangun pipeline scikit-learn, pola ini mirip dengan komposisi Pipeline dan ColumnTransformer untuk feature engineering yang juga lazy dan deklaratif.
Benchmark performa: groupby, join, dan agregasi
Saya menjalankan TPC-H scale factor 10 (sekitar 10 GB Parquet) pada AMD Ryzen 9 7950X (16 core) dengan 64 GB RAM, Polars 1.21, dan Pandas 2.2 dengan PyArrow backend. Hasil rata-rata dari lima eksekusi:
Query (TPC-H SF10)
Polars 1.21 (detik)
Pandas 2.2 + PyArrow (detik)
Speedup
Q1 (group + agg sederhana)
0.42
6.8
16x
Q3 (join 3 tabel + filter + agg)
1.1
21.3
19x
Q5 (join 6 tabel)
2.3
OOM*
n/a
Q10 (join + window function)
1.8
34.1
19x
*OOM = out of memory. Pandas tidak dapat menyelesaikan Q5 pada 64 GB RAM karena join intermediate-nya membengkak. Polars menanganinya tanpa masalah dengan streaming engine. Untuk hasil yang dapat direproduksi, lihat benchmark resmi Polars yang juga membandingkan dengan DuckDB, Dask, dan Modin.
Streaming engine untuk data lebih besar dari RAM
Salah satu pembeda terbesar Polars sejak versi 1.x adalah streaming engine, yaitu mode eksekusi yang memproses LazyFrame dalam chunk kecil sehingga dapat menangani dataset jauh lebih besar dari memori. Aktifkan dengan parameter engine="streaming" pada collect().
import polars as pl
# Dataset 50 GB Parquet, RAM hanya 16 GB
lf = pl.scan_parquet("log_2025_*.parquet")
hasil = (
lf.filter(pl.col("level") == "ERROR")
.group_by(["service", pl.col("ts").dt.truncate("1h")])
.agg(
pl.len().alias("jumlah_error"),
pl.col("latency_ms").quantile(0.95).alias("p95_latency"),
)
.sort(["service", "ts"])
.collect(engine="streaming") # proses dalam chunk
)
print(f"Total grup: {len(hasil)}")
Streaming engine bekerja paling baik untuk operasi yang dapat dipartisi: filter, projection, group_by dengan hash, dan join hash. Window function global dan sort penuh tetap membutuhkan materialisasi sehingga mungkin gagal pada dataset sangat besar. Untuk kombinasi join Polars dengan SQL ad-hoc, kombinasikan dengan DuckDB. Lihat pembahasan DuckDB untuk query SQL pada Pandas dan Parquet yang juga membahas pola streaming yang serupa.
Cara migrasi dari Pandas ke Polars selangkah demi selangkah
Migrasi yang sukses jarang sekali rewrite total. Pendekatan yang saya pakai untuk klien selama dua tahun terakhir adalah migrasi inkremental berdasarkan profil performa:
Identifikasi bottleneck. Jalankan cProfile atau py-spy pada pipeline. Cari fungsi Pandas yang mendominasi waktu eksekusi, biasanya groupby.apply, merge berskala besar, atau read_csv pada file besar.
Mulai dari I/O. Ganti pd.read_parquet() dengan pl.read_parquet().to_pandas() sebagai langkah pertama. Anda dapat speedup pembacaan 3-5x tanpa mengubah kode hilir.
Konversi tahap berat menjadi Polars. Untuk tahap transformasi yang berat (groupby + agg + join), tulis ulang sebagai LazyFrame, lalu konversi kembali ke Pandas hanya jika tahap berikutnya menggunakan library Pandas-only.
Migrasi akhir-ke-akhir. Setelah ekosistem Anda (scikit-learn 1.4+, seaborn 0.13+, statsmodels 0.15+) menerima Polars langsung, hapus konversi perantara dan jalankan pipeline penuh sebagai LazyFrame.
import polars as pl
import pandas as pd
# Langkah 2: hibrida (Polars untuk I/O, Pandas untuk sisanya)
df_pd = pl.read_parquet("data.parquet").to_pandas()
# ... kode Pandas yang sudah ada tetap jalan ...
# Langkah 3: hibrida (Polars untuk transform berat)
ringkasan = (
pl.scan_parquet("data.parquet")
.filter(pl.col("region") == "ID")
.group_by("kategori")
.agg(pl.col("nilai").sum())
.collect()
.to_pandas() # serahkan ke scikit-learn atau plotting
)
# Konversi balik gratis (zero-copy) jika kolom Pandas sudah Arrow-backed
df_pl = pl.from_pandas(df_pd)
Untuk pipeline analisis temporal yang sebelumnya memakai resample dan rolling window di Pandas, Polars menyediakan padanan langsung lewat group_by_dynamic dan rolling. Sintaksnya berbeda tapi konsepnya identik, dan biasanya 10-20x lebih cepat pada data tahunan tick.
Kapan tetap memilih Pandas
Meski saya bias ke Polars untuk pipeline produksi, ada situasi di mana Pandas masih pilihan tepat. Pertama, kompatibilitas ekosistem. Banyak library statistik (statsmodels, linearmodels, arch untuk model GARCH) dan tool publikasi (great_tables, beberapa plugin Jupyter) masih mengasumsikan DataFrame Pandas. Kedua, dataset kecil di bawah 100 MB, karena overhead memulai Polars dan kebiasaan tim sering lebih mahal dari speedup yang didapat. Ketiga, kompatibilitas dengan kode legacy yang sudah ada dan tutorial pelatihan internal yang berbasis Pandas.
Pada 2026, rilis Pandas 3.0 juga membawa peningkatan signifikan: PyArrow sebagai backend default, mode copy-on-write yang konsisten, dan dukungan tipe data nullable yang lebih bersih. Selisih performanya dengan Polars menyempit untuk operasi single-thread tapi tetap signifikan untuk groupby dan join paralel. Detail lengkap di catatan rilis Pandas 3.0.
Rekomendasi praktis saya: jika tim Anda baru memulai proyek data 2026, mulailah dengan Polars. Kalau Anda memelihara pipeline Pandas yang berjalan baik dengan dataset di bawah 1 GB, tidak ada urgensi migrasi — fokuskan migrasi pada pipeline yang menjadi bottleneck biaya komputasi atau waktu iterasi.
Pertanyaan yang sering diajukan
Apakah Polars benar-benar lebih cepat dari Pandas?
Ya, untuk operasi groupby, join, dan agregasi pada dataset di atas 100 MB, Polars biasanya 5-30x lebih cepat dari Pandas 2.x karena multi-threading dan query optimizer. Untuk dataset sangat kecil atau operasi row-wise sederhana, perbedaannya kecil dan kadang Pandas malah menang karena overhead startup yang lebih rendah.
Apakah saya perlu belajar Polars jika sudah mahir Pandas?
Jika Anda bekerja dengan dataset di atas 1 GB atau membangun pipeline produksi, sangat disarankan. Untuk analisis ad-hoc dataset kecil, Pandas tetap memadai. Kabar baiknya, kurva belajar Polars hanya beberapa hari untuk pengguna Pandas berpengalaman karena konsep DataFrame, groupby, dan join identik.
Bisakah Polars menggantikan Pandas sepenuhnya?
Secara fungsionalitas DataFrame, ya. Namun ekosistem Pandas masih lebih besar. Banyak library statsmodels, ekonometrika, dan visualisasi mengharapkan DataFrame Pandas. Polars menyediakan to_pandas() zero-copy untuk kasus ini, sehingga Anda bisa menggunakan Polars sebagai engine utama dan konversi hanya pada titik integrasi.
Apa itu LazyFrame di Polars?
LazyFrame adalah representasi DataFrame yang menyimpan operasi sebagai logical plan tanpa mengeksekusinya. Anda merangkai filter, select, group_by, lalu memanggil .collect() untuk menjalankan query yang sudah dioptimasi oleh query planner. Ini memungkinkan predicate pushdown ke level file reader dan projection pruning.
Apakah Polars mendukung GPU?
Ya, sejak Polars 1.x tersedia GPU engine berbasis NVIDIA cuDF yang diaktifkan dengan collect(engine="gpu"). Statusnya masih preview di 2026 dan tidak semua operasi didukung, tetapi untuk groupby dan agregasi pada data 10-100 GB pada GPU A100, speedup tambahan 2-5x di atas CPU Polars sudah dapat dicapai.
Bagaimana cara konversi DataFrame Pandas ke Polars?
Gunakan pl.from_pandas(df) untuk konversi Pandas ke Polars dan polars_df.to_pandas() untuk arah sebaliknya. Jika DataFrame Pandas Anda sudah menggunakan tipe Arrow (Pandas 2.x dengan dtype_backend="pyarrow"), konversinya zero-copy dan praktis instan bahkan pada dataset multi-gigabyte.
Pandera 0.22 mengubah kontrak data jadi kode Python berbasis class. Panduan validasi Pandas dan Polars di pipeline produksi, dari DataFrameModel sampai integrasi dbt, Airflow, dan FastAPI.
Playbook production serving model scikit-learn dengan FastAPI: Pydantic V2, lifespan handler, micro-batching, ONNX Runtime, Uvicorn+Gunicorn, dan monitoring Prometheus untuk p99 di bawah 30 ms.
DuckDB Python memungkinkan Anda menjalankan SQL standar langsung di atas Pandas DataFrame dan file Parquet. Pelajari instalasi, contoh kode, perbandingan dengan Pandas dan Polars, serta studi kasus ETL 100 juta baris log di laptop.