Tracks
Trong thế giới phân tích dữ liệu, pandas từ lâu đã là lựa chọn mặc định để xử lý dữ liệu dạng bảng trong Python đối với các chuyên gia dữ liệu.
Tuy nhiên, khi tập dữ liệu ngày càng lớn và phức tạp, pandas có thể gặp nút thắt cổ chai về hiệu năng, khả năng tận dụng đa lõi hạn chế và ràng buộc về bộ nhớ.
Đó là lúc Polars xuất hiện như một lựa chọn hiện đại thay thế. Polars là thư viện DataFrame được viết bằng Rust, cung cấp hiệu năng cực nhanh, quản lý bộ nhớ hiệu quả và triết lý thiết kế tập trung vào khả năng mở rộng.
Trong hướng dẫn này, chúng tôi sẽ giới thiệu Polars là gì và cách thực hiện một số thao tác cơ bản với Polars trong Python. Nếu bạn muốn thực hành trực tiếp, tôi khuyên bạn nên xem khóa học Introduction to Polars.
Các tính năng chính của Python Polars

Polars mang đến một bộ tính năng độc đáo giúp nó khác biệt với pandas:
- Nền tảng Rust: An toàn và hiệu năng ở cấp độ hệ thống.
- Thực thi đa luồng: Tận dụng tối đa CPU hiện đại.
- Đánh giá lười (lazy evaluation): Hoãn thực thi cho đến khi thực sự cần.
- Áp đặt lược đồ (schema): Đảm bảo xử lý dữ liệu nhất quán.
- Hỗ trợ kiểu dữ liệu nâng cao: Xử lý tự nhiên các kiểu thời gian, phân loại và lồng nhau.
Các kiểu dữ liệu trong Polars
Polars hỗ trợ nhiều kiểu dữ liệu vượt ra ngoài những kiểu cơ bản:
- Số:
Int32,Int64,Float32,Float64. - Boolean: giá trị
true/false. - Thời gian:
Date,Datetime,Duration,Time. - Phân loại (Categorical): Chuỗi được mã hóa để lưu trữ tiết kiệm bộ nhớ.
- Lồng nhau: kiểu
ListvàStruct, hữu ích cho dữ liệu giống JSON.
Ưu điểm so với pandas
Là lựa chọn mới hơn và hiện đại hơn so với pandas, Polars mang lại nhiều lợi ích:
- Thực thi nhanh hơn trên các tập dữ liệu lớn.
- Tiết kiệm bộ nhớ hơn.
- Phù hợp hơn cho pipeline ETL và môi trường sản xuất.
- Tối ưu tích hợp như predicate và projection pushdown.
Cài đặt và thiết lập môi trường cho Python Polars
Bây giờ, hãy xem cách bạn có thể bắt đầu sử dụng Polars trong Python.
Trước khi dùng Polars, bạn cần thiết lập môi trường cho đúng.
Nền tảng được hỗ trợ
Polars hỗ trợ Windows, macOS và Linux. Có thể cài đặt trong môi trường ảo, Python hệ thống hoặc qua quy trình đóng gói (Docker).
Cài đặt bằng pip
Để cài đặt thư viện polars trong Python, chạy lệnh sau trong terminal.
pip install polars
Bạn sẽ thấy thông báo cài đặt như sau:

Cài đặt bằng conda
Ngoài ra, bạn có thể cài đặt thư viện trong môi trường conda nếu đó là môi trường bạn đang sử dụng.
conda install -c conda-forge polars
Xác minh cài đặt
Để kiểm tra cài đặt đã thành công hay chưa, viết đoạn script đơn giản sau:
import polars as pl
print(pl.__version__)
Cấu hình và biến môi trường
Polars cho phép tinh chỉnh cách chạy và cách hiển thị đầu ra bằng cách đặt các biến môi trường trước khi bắt đầu phiên Python. Ví dụ:
POLARS_MAX_THREADS: Giới hạn số luồng.POLARS_FMT_MAX_COLS: Kiểm soát số cột được in ra.POLARS_FMT_TABLE_WIDTH: Điều chỉnh độ rộng hiển thị DataFrame.
Dưới đây là ví dụ về cách đặt các biến này trong shell trước khi chạy Python:
export POLARS_MAX_THREADS=8
export POLARS_FMT_MAX_COLS=20
Tạo bộ dữ liệu CSV mẫu để minh họa
Trước khi đi sâu vào các tính năng của Polars, sẽ hữu ích nếu có một tập dữ liệu để dùng nhất quán trong suốt hướng dẫn này. Chúng ta có thể tạo một tệp CSV đơn giản bằng mô-đun csv tích hợp của Python hoặc pandas.
Dưới đây là ví dụ tạo tệp transactions.csv với dữ liệu tổng hợp:
import csv
import random
from datetime import datetime, timedelta
# Define column names
columns = ["transaction_id", "customer_id", "amount", "transaction_date"]
# Generate synthetic rows
rows = []
start_date = datetime(2023, 1, 1)
for i in range(1, 101):
customer_id = random.randint(1, 10)
amount = round(random.uniform(10, 2000), 2)
date = start_date + timedelta(days=random.randint(0, 90))
rows.append([i, customer_id, amount, date.strftime("%Y-%m-%d")])
# Write to CSV
with open("transactions.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(columns)
writer.writerows(rows)
Script này tạo một tập dữ liệu gồm 100 giao dịch với số tiền, mã khách hàng và ngày giao dịch ngẫu nhiên. Bạn có thể điều chỉnh phạm vi và kích thước theo nhu cầu.
Lưu script này, chạy một lần và bạn sẽ có một tệp CSV để dùng trong các ví dụ xuyên suốt bài viết.
Các khái niệm cốt lõi trong DataFrame và Series của Python Polars
Polars được xây dựng dựa trên hai trừu tượng cốt lõi: Series và DataFrame.
Kết hợp lại, chúng cung cấp cách làm việc với dữ liệu có cấu trúc và hiệu quả, tương tự tinh thần của pandas nhưng được tối ưu bởi backend Rust của Polars. Hãy cùng phân tích các khái niệm chính.
Series: Mảng 1 chiều với kiểu xác định
Series trong Polars là một mảng một chiều, giống như một cột trong bảng tính hoặc bảng cơ sở dữ liệu. Mỗi Series có:
- Một tên (nhãn cột).
- Một kiểu dữ liệu (như
Int64,Utf8,Float64,Boolean, v.v.). - Một tập giá trị có thứ tự.
Vì kiểu dữ liệu được áp đặt chặt chẽ, Series trong Polars thường nhanh hơn và dễ dự đoán hơn so với danh sách Python.
Ví dụ:
import polars as pl
# Create a Series of integers
s = pl.Series("numbers", [1, 2, 3, 4, 5])
print(s)
Đầu ra:
shape: (5,)
Series: 'numbers' [i64]
[
1
2
3
4
5
]
DataFrame: Tập hợp các series
DataFrame là cấu trúc hai chiều tổ chức nhiều Series theo một lược đồ. Về khái niệm, nó giống như một bảng trong SQL hoặc Excel. Hàng biểu diễn các bản ghi và cột biểu diễn các trường.
Ví dụ:
df = pl.DataFrame({
"id": [1, 2, 3],
"name": ["Alice", "Bob", "Charlie"],
"age": [25, 30, 35]
})
print(df)
Đầu ra:
shape: (3, 3)
┌─────┬─────────┬─────┐
│ id │ name │ age │
│ --- │ --- │ --- │
│ i64 │ str │ i64 │
├─────┼─────────┼─────┤
│ 1 │ Alice │ 25 │
│ 2 │ Bob │ 30 │
│ 3 │ Charlie │ 35 │
└─────┴─────────┴─────┘
Mỗi cột là một Series và DataFrame áp đặt lược đồ của nó.
Vai trò của lược đồ và tính nhất quán kiểu nghiêm ngặt
Một điểm mạnh của Polars là áp đặt lược đồ nghiêm ngặt. Mỗi cột có kiểu dữ liệu cố định và Polars đảm bảo mọi thao tác đều tôn trọng kiểu đó. Điều này ngăn các lỗi tinh vi thường gặp trong các phép toán kiểu động.
Ví dụ, bạn không thể vô tình cộng một cột chuỗi với một cột số nguyên nếu không chuyển đổi rõ ràng.
Ví dụ:
df = df.with_columns(
(pl.col("age") + 5).alias("age_plus_5")
)
print(df)
Ở đây, age là i64 và kết quả vẫn là số nguyên. Nếu bạn thử cộng một cột chuỗi, Polars sẽ báo lỗi thay vì âm thầm thất bại.
Xử lý giá trị null
Dữ liệu thực tế thường có giá trị thiếu, và Polars cung cấp công cụ rõ ràng để xử lý chúng:
fill_null(): Thay null bằng một giá trị cho trước.drop_nulls(): Loại bỏ các hàng chứa null.is_null()/is_not_null(): Kiểm tra Boolean.
Biểu thức: Các phép toán cột dạng vector
Polars thúc đẩy hệ thống biểu thức, trong đó các thao tác được định nghĩa là biến đổi trên cột thay vì các vòng lặp Python theo hàng.
Các biểu thức này được vector hóa, nghĩa là chúng hoạt động trên toàn bộ cột cùng lúc, nhanh hơn nhiều.
Thay vì lặp thủ công, Polars xây dựng phép tính vector hóa nhanh.
Thực thi eager và lazy
Polars cung cấp hai chế độ thực thi:
1. Thực thi eager
- Chạy phép tính ngay lập tức.
- Tương tự pandas.
- Tuyệt vời cho khám phá tương tác và tập dữ liệu nhỏ đến vừa.
Ví dụ về thực thi eager:
df = pl.DataFrame({"x": [1, 2, 3]})
print(df.select(pl.col("x") * 2)) # eager: runs instantly
2. Thực thi lazy
- Xây dựng một kế hoạch truy vấn thay vì thực thi ngay.
- Polars tối ưu kế hoạch này bên dưới (predicate pushdown, song song hóa, cắt tỉa cột).
- Lý tưởng cho tập dữ liệu lớn và biến đổi phức tạp.
Ví dụ về thực thi lazy:
lazy_df = pl.DataFrame({"x": [1, 2, 3]}).lazy()
result = lazy_df.select(pl.col("x") * 2).collect() # execute on collect()
print(result)
Ở đây, không có gì được tính cho đến khi gọi .collect(). Trong các quy trình lớn, điều này có thể mang lại cải thiện hiệu năng đáng kể.
Các thao tác DataFrame cơ bản trong Python Polars
Tiếp theo, chúng ta sẽ thực hiện một số thao tác cơ bản với Polars trên tập dữ liệu đã tạo.
Nạp tập dữ liệu
Polars có thể nạp dữ liệu từ nhiều định dạng tệp và đối tượng trong bộ nhớ. Điều này giúp linh hoạt khi tích hợp vào các pipeline dữ liệu hiện đại.
Dưới đây là cách làm với các nguồn khác nhau:
Từ tập CSV ta đã tạo trước đó:
import polars as pl
df = pl.read_csv("transactions.csv")
print(df.head())
Chúng ta cũng có thể đọc tập dữ liệu từ Parquet nếu cần.
df_parquet = pl.read_parquet("transactions.parquet")
Nếu bạn có tệp JSON, bạn có thể đọc bằng đoạn mã sau:
df_json = pl.read_json("transactions.json")
#For JSON Lines (NDJSON), use the following instead:
df_json = pl.read_ndjson("transactions.json")
Cách đọc dữ liệu từ Arrow Table:
import pyarrow as pa
arrow_table = pa.table({
"transaction_id": [1, 2],
"customer_id": [5, 7],
"amount": [150.25, 300.75],
"transaction_date": ["2023-01-02", "2023-01-03"]
})
df_arrow = pl.from_arrow(arrow_table)
Chọn và lọc
Bây giờ hãy chọn các cột hoặc hàng cụ thể từ tập dữ liệu của chúng ta.
Chọn cột
Khi dùng Polars, thao tác thường gặp là chọn những cột bạn muốn làm việc và giữ lại.
Cách thực hiện như sau:
# Select only transaction_id and amount
df.select(["transaction_id", "amount"])
Lọc hàng
Bạn cũng có thể lọc hàng dựa trên các điều kiện, tương tự pandas.
# Get only high-value transactions above $1,000
high_value = df.filter(pl.col("amount") > 1000)
print(high_value)
Áp dụng biểu thức
Áp dụng biểu thức trong Polars liên quan đến việc sử dụng đối tượng polars.Expr trong các ngữ cảnh khác nhau để thực hiện biến đổi dữ liệu.
Bạn có thể tạo chúng bằng pl.col() hoặc pl.lit().
# Add a 10% discount column to simulate promotional pricing
df.select([
pl.col("transaction_id"),
pl.col("amount"),
(pl.col("amount") * 0.9).alias("discounted_amount")
])
Tổng hợp (Aggregations)
Chúng ta có thể phân tích thói quen chi tiêu theo khách hàng bằng group_by.
# Total and average spend per customer
agg_df = df.group_by("customer_id").agg([
pl.sum("amount").alias("total_spent"),
pl.mean("amount").alias("avg_transaction")
])
print(agg_df)
Đầu ra mẫu:
shape: (10, 3)
┌─────────────┬────────────┬───────────────┐
│ customer_id │ total_spent│ avg_transaction│
│ --- │ --- │ --- │
│ i64 │ f64 │ f64 │
├─────────────┼────────────┼───────────────┤
│ 1 │ 5230.12 │ 523.01 │
│ 2 │ 6120.45 │ 680.05 │
│ ... │ ... │ ... │
└─────────────┴────────────┴───────────────┘
Xử lý giá trị thiếu
Tập dữ liệu sinh ra của chúng ta mặc định không có null, nhưng hãy giả lập cách xử lý nếu có.
Điền giá trị thiếu
Giá trị thiếu có thể gây vấn đề trong phân tích hạ nguồn và trực quan hóa dữ liệu. Bạn sẽ cần điền các giá trị thiếu để mọi thứ diễn ra trơn tru.
Cách điền giá trị thiếu:
# Imagine 'amount' has missing values, then replace with 0
df_filled = df.with_columns(
pl.col("amount").fill_null(0)
)
Loại bỏ null
Null có thể gây lỗi nếu không xử lý. Cách loại bỏ như sau:
df_no_nulls = df.drop_nulls()
Chuyển đổi kiểu
Kiểu dữ liệu có thể bị định dạng sai trong một tập dữ liệu. Dưới đây là cách chuyển đổi bằng phương thức .cast:
# Ensure customer_id is treated as string instead of int
df_casted = df.with_columns(
pl.col("customer_id").cast(pl.Utf8)
)
Xâu chuỗi thao tác
Polars cho phép xâu chuỗi phương thức để quy trình làm việc gọn gàng hơn. Cách xâu chuỗi này thường dùng trong SQL hoặc lập trình R với gói tidyverse.
Ví dụ: Tìm khách hàng chi tiêu nhiều nhất trong tháng 3
pipeline = (
df
.with_columns(pl.col("transaction_date").str.strptime(pl.Date, format="%Y-%m-%d"))
#.col("date_str").str.to_date(format="%Y-%m-%d")
.filter(pl.col("transaction_date").dt.month() == 3) # transactions in March
.group_by("customer_id")
.agg(pl.sum("amount").alias("march_spent"))
.sort("march_spent", descending=True)
)
print(pipeline)
Pipeline này:
- Lọc các giao dịch trong tháng 3.
- Gom nhóm theo khách hàng.
- Tổng hợp chi tiêu.
- Sắp xếp theo tổng chi tiêu.
Cách xâu chuỗi này cho phép phân tích theo pipeline mà không cần dùng các DataFrame trung gian.
Tính năng nâng cao và đánh giá lười trong Polars
Vượt ra ngoài các thao tác cơ bản, Polars tỏa sáng khi làm việc với tập dữ liệu lớn nhờ động cơ đánh giá lười. Mô hình này cho phép Polars xây dựng kế hoạch truy vấn trước, tối ưu bên dưới rồi mới thực thi pipeline. Kết quả là hiệu năng và hiệu quả được cải thiện mạnh, đặc biệt với hàng triệu dòng hoặc biến đổi phức tạp.
Mặc định, Polars chạy ở chế độ eager. Điều này nghĩa là phép tính xảy ra ngay, tương tự pandas. Chế độ lazy thì khác:
- Mỗi thao tác (filter, select, group_by) được ghi nhận thay vì thực thi ngay.
- Chỉ khi bạn gọi
.collect()thì các biến đổi mới được thực hiện. - Việc hoãn công việc cho phép Polars phân tích toàn bộ pipeline và chạy theo cách hiệu quả nhất có thể.
Ví dụ chế độ lazy:
import polars as pl
# Load dataset in lazy mode
lazy_df = pl.scan_csv("transactions.csv")
# Build a transformation pipeline
pipeline = (
lazy_df
.filter(pl.col("amount") > 1000) # step 1: filter expensive transactions
.group_by("customer_id") # step 2: group by customer
.agg(pl.sum("amount").alias("total_spent")) # step 3: aggregate
)
# Nothing has run yet, computation happens only on collect()
result = pipeline.collect()
print(result)
Tối ưu truy vấn
Polars tối ưu truy vấn bằng cách áp dụng kỹ thuật pushdown:
- Predicate Pushdown: Bộ lọc được đẩy sát nguồn dữ liệu nhất có thể. Ví dụ: Khi lọc
amount > 1000, Polars áp dụng bộ lọc khi đọc CSV thay vì sau khi nạp toàn bộ hàng. - Projection Pushdown: Chỉ các cột cần thiết mới được đọc vào bộ nhớ. Ví dụ: Nếu bạn chỉ chọn
customer_idvàamount, Polars sẽ bỏ qua việc đọctransaction_datehoàn toàn.
Streaming cho dữ liệu lớn
Khi dữ liệu quá lớn để chứa trong bộ nhớ, Polars cung cấp thực thi dạng streaming. Thay vì nạp mọi thứ cùng lúc, Polars xử lý dữ liệu theo lô, giữ mức sử dụng bộ nhớ ổn định.
Điều này đặc biệt hữu ích với các tệp CSV hoặc Parquet nhiều GB.
Ví dụ (chế độ streaming):
# Enable streaming execution for huge datasets
stream_result = (
lazy_df
.group_by("customer_id")
.agg(pl.sum("amount").alias("total_spent"))
.collect(streaming=True) # execute in streaming mode
)
Với streaming=True, Polars tránh tạo các bảng trung gian khổng lồ trong bộ nhớ, giúp mở rộng tốt hơn pandas cho khối lượng công việc lớn.
Thực thi với .collect() và gỡ lỗi truy vấn lazy
Phương thức .collect() là nút kích hoạt thực thi pipeline lazy. Trước đó, bạn có thể kiểm tra và gỡ lỗi kế hoạch truy vấn với:
.describe_plan(): Hiển thị kế hoạch logic..describe_optimized_plan(): Hiển thị kế hoạch đã tối ưu sau khi Polars áp dụng pushdown và đơn giản hóa.
Tối ưu hiệu năng và hiệu quả của Python Polars
Polars có thể giúp tăng tốc pipeline phân tích của bạn.
Dưới đây là một số thực tiễn tốt:
- Dùng đánh giá lười cho các pipeline lớn.
- Giảm thiểu chuyển đổi kiểu.
- Tránh vật chất hóa không cần thiết các DataFrame trung gian.
Join, gộp và kết hợp dữ liệu trong Python Polars
Phân tích thực tế thường cần kết hợp các tập dữ liệu. Polars cung cấp đầy đủ các phép join với thực thi tối ưu, giúp gộp các bảng lớn một cách dễ dàng.
Các kiểu join được hỗ trợ
Polars hỗ trợ tất cả các kiểu join chính:
- Inner Join: Giữ lại các hàng khớp nhau.
- Left / Right Join: Giữ toàn bộ hàng từ một phía.
- Outer Join: Giữ tất cả hàng, điền thiếu bằng null.
- Semi Join: Giữ các hàng bên trái có khớp ở bên phải.
- Anti Join: Giữ các hàng bên trái không có khớp ở bên phải.
- Cross Join: Tích Descartes của hai bảng.
Ví dụ: Join giao dịch với metadata khách hàng
# Create customer metadata DataFrame
customers = pl.DataFrame({
"customer_id": [1, 2, 3, 4, 5],
"customer_name": ["Alice", "Bob", "Charlie", "David", "Eva"]
})
# Inner join on customer_id
df_joined = df.join(customers, on="customer_id", how="inner")
print(df_joined.head())
Join của Polars so với Pandas về hiệu năng và khả năng sử dụng
Polars vượt trội hơn Pandas ở cả hai khía cạnh:
- Hiệu năng: Join của Polars được hiện thực bằng Rust với khả năng song song, nên nhanh hơn trên tập dữ liệu lớn so với pandas. Predicate và projection pushdown cũng áp dụng cho join, giảm di chuyển dữ liệu không cần thiết.
- Khả năng sử dụng: Polars yêu cầu khóa join rõ ràng, tránh các join vô tình dựa trên căn chỉnh chỉ mục (pitfall thường gặp ở pandas). Semi và anti join là chức năng gốc trong Polars, trong khi ở pandas cần thủ thuật.
Hàm cửa sổ và phép toán rolling trong Polars
Hàm cửa sổ cho phép tính toán trong phạm vi nhóm hoặc theo các hàng có thứ tự, mà không làm gộp kết quả, tương tự hàm cửa sổ trong SQL.
Polars cho phép tính thống kê theo khách hàng hoặc theo giai đoạn thời gian bằng ngữ cảnh cửa sổ.
Dưới đây là một số ví dụ về hàm cửa sổ bạn có thể dùng trong Polars:
- Trung bình/tổng rolling cho đường trung bình động.
- Cửa sổ mở rộng (expanding) cho thống kê tích lũy.
- Hàm xếp hạng cho phân tích dựa trên thứ tự.
1. Hàm chạy (running)
Ví dụ: Tổng tích lũy theo khách hàng
df_window = df.with_columns( pl.col("amount") .sort_by("transaction_date") .cum_sum() .over("customer_id") .alias("running_total") )
print(df_window.head())
2. Hàm rolling
Hàm rolling hoạt động trên một cửa sổ trượt của các hàng hoặc thời gian.
Ví dụ: Tổng rolling 7 ngày của giao dịch
df = df.with_columns(pl.col("transaction_date").str.strptime(pl.Date, format="%Y-%m-%d"))
rolling = (
df.group_by_rolling("transaction_date", period="7d")
.agg(pl.sum("amount").alias("rolling_7d_sum"))
)
print(rolling.head())
Cửa sổ mở rộng (tích lũy) và cửa sổ căn giữa cũng được hỗ trợ bằng cách điều chỉnh tham số.
3. Hàm xếp hạng
Bạn có thể dùng các hàm xếp hạng và tổng hợp tùy chỉnh trong ngữ cảnh cửa sổ.
Ví dụ: Xếp hạng giao dịch theo khách hàng dựa trên số tiền
ranked = df.with_columns(
pl.col("amount").rank("dense", descending=True).over("customer_id").alias("rank")
)
print(ranked.head())
Điều này tạo ra xếp hạng (1 = cao nhất) cho mức chi tiêu của mỗi khách hàng.
Hàm cửa sổ cho phép các phép tính theo ngữ cảnh:
print(
df.group_by("customer_id").agg(pl.col("amount").cum_sum().alias("cumulative_spent"))
)
Sử dụng truy vấn SQL trong Python Polars
Đối với các nhà phân tích quen với SQL, Polars cung cấp ngữ cảnh SQL để bạn có thể truy vấn DataFrame trực tiếp bằng cú pháp SQL trong khi vẫn tận dụng tốc độ của Polars.
Ngữ cảnh SQL và đăng ký DataFrame
Để bắt đầu, bạn phải đăng ký một DataFrame trước khi chạy SQL.
from polars import SQLContext
ctx = SQLContext()
ctx.register("transactions", df)
Chạy truy vấn SQL trực tiếp trong Polars
Hãy xem ví dụ cách chạy truy vấn SQL trong Python bằng Polars.
Ví dụ: Truy vấn tổng chi theo khách hàng bằng SQL
result = ctx.execute("""
SELECT customer_id, SUM(amount) AS total_spent
FROM transactions
GROUP BY customer_id
ORDER BY total_spent DESC
""").collect()
print(result)
Tích hợp SQL với biểu thức Polars
Bạn có thể kết hợp SQL và biểu thức:
sql_result = ctx.execute("SELECT * FROM transactions WHERE amount > 1500")
df_sql = sql_result.collect()
# Continue with Polars expressions
df_sql = df_sql.with_columns((pl.col("amount") * 0.95).alias("discounted"))
Điều này hữu ích cho các nhóm đang chuyển đổi từ công cụ dựa trên SQL.
Tích hợp Python Polars với hệ sinh thái rộng hơn
Polars không được thiết kế như một hòn đảo độc lập, mà là thư viện DataFrame hiệu năng cao tương thích tốt với hệ sinh thái dữ liệu Python rộng lớn. Tính tương tác này đảm bảo nhà phân tích và kỹ sư có thể áp dụng Polars dần dần trong khi vẫn tận dụng các công cụ hiện có.
Một số khía cạnh tích hợp:
- Khả năng tương tác gói: Chuyển đổi liền mạch giữa Polars, pandas, NumPy, Arrow.
- Trực quan hóa: Dùng matplotlib, seaborn hoặc plotly để vẽ biểu đồ.
- Học máy: Đưa DataFrame của Polars vào pipeline scikit-learn, PyTorch hoặc TensorFlow.
- Đám mây & CSDL: I/O hiệu quả với Parquet, Arrow và các kết nối tới lưu trữ đám mây.
- Jupyter notebooks: Polars tích hợp mượt trong môi trường tương tác.
Ví dụ và các trường hợp sử dụng phổ biến của Python Polars
Cuối cùng, hãy nhanh chóng xem một vài ví dụ về việc sử dụng Polars:
1. Làm sạch dữ liệu
df = df.with_columns([
pl.col("transaction_date").str.strptime(pl.Date, "%Y-%m-%d").alias("txn_date"),
pl.col("amount").fill_null(strategy="mean")
])
2. Pipeline ETL
result = (
pl.read_csv("transactions.csv")
.lazy()
.filter(pl.col("amount") > 1000)
.group_by("customer_id")
.agg(pl.sum("amount").alias("total_spent"))
.collect()
)
3. Tài chính
Dưới đây là ví dụ về đường trung bình động cho số tiền giao dịch.
import polars as pl
# Load & parse dates
df = (
pl.read_csv("transactions.csv")
.with_columns(pl.col("transaction_date").str.strptime(pl.Date, "%Y-%m-%d"))
)
# (A) Overall: daily totals + 7-day rolling average
daily = (
df.sort("transaction_date")
.group_by_dynamic("transaction_date", every="1d")
.agg(pl.sum("amount").alias("daily_total"))
.sort("transaction_date")
.with_columns(
pl.col("daily_total").rolling_mean(window_size=7).alias("ma7")
)
)
# (B) Per-customer: daily totals + 7-day rolling average within each customer
daily_by_cust = (
df.sort("transaction_date")
.group_by_dynamic(index_column="transaction_date", every="1d", by="customer_id")
.agg(pl.sum("amount").alias("daily_total"))
.sort(["customer_id", "transaction_date"])
.with_columns(
pl.col("daily_total")
.rolling_mean(window_size=7)
.over("customer_id")
.alias("ma7_per_customer")
)
)
print(daily.tail())
print(daily_by_cust.filter(pl.col("customer_id")==1).tail())
Kết quả dự kiến như sau:

4. Tính toán khoa học
Khi làm tính toán khoa học, bạn sẽ cần xử lý hiệu quả hàng triệu dòng dữ liệu thí nghiệm hoặc dữ liệu mô phỏng giống giao dịch.
Dưới đây là một hiện thực mẫu:
import polars as pl
# Assume a very large Parquet file with columns: id, value, ts (UTC)
# Use lazy scan_* to avoid loading into memory up-front
lazy = (
pl.scan_parquet("experiments.parquet") # or: pl.scan_csv("experiments.csv")
.filter(pl.col("value") > 0) # predicate pushdown
.select(["id", "value", "ts"]) # projection pushdown
.with_columns(
# Example transformations: standardization & bucketize timestamps by hour
((pl.col("value") - pl.col("value").mean()) / pl.col("value").std())
.alias("z_value"),
pl.col("ts").dt.truncate("1h").alias("ts_hour")
)
.group_by(["id", "ts_hour"])
.agg([
pl.len().alias("n"),
pl.mean("z_value").alias("z_mean"),
pl.std("z_value").alias("z_std")
])
.sort(["id", "ts_hour"])
)
# Execute in streaming mode to keep memory usage low
result = lazy.collect(streaming=True)
# Optionally write out partitioned Parquet for downstream analysis
result.write_parquet("experiments_hourly_stats.parquet")
print(result.head())
Lời kết
Python Polars mang đến một thư viện DataFrame hiện đại, hiệu năng cao, khắc phục nhiều hạn chế của pandas. Dù pandas vẫn phổ biến cho các phân tích nhỏ, ad-hoc, Polars ngày càng trở thành công cụ được ưa chuộng cho xử lý dữ liệu quy mô lớn, hiệu quả và đáng tin cậy trong Python.
Muốn tìm hiểu thêm về Polars? Bạn sẽ thích khóa học Introduction to Polars của chúng tôi hoặc bài viết Introduction to Polars. Bài viết về Polars Engine của chúng tôi cũng có thể khiến bạn quan tâm.
Python Polars FAQs
Sự khác nhau chính giữa Polars và Pandas là gì?
Polars nhanh hơn và tiết kiệm bộ nhớ hơn vì được xây dựng bằng Rust và sử dụng động cơ dựa trên cột. Nó hỗ trợ cả chế độ lazy và eager, trong khi pandas chỉ hoạt động ở chế độ eager. Pandas dễ dùng hơn cho tác vụ nhỏ, còn Polars phù hợp hơn cho dữ liệu lớn và hiệu năng.
Polars xử lý tập dữ liệu lớn như thế nào so với Pandas?
Polars có thể xử lý tệp lớn mà không cần nạp tất cả vào bộ nhớ cùng lúc. Nó chỉ đọc các cột và hàng cần thiết, và chạy thao tác song song. Pandas nạp toàn bộ tập dữ liệu vào bộ nhớ và thường chạy trên một luồng, có thể chậm hơn và nặng hơn.
Bạn có thể giải thích khái niệm đánh giá lười (lazy evaluation) trong Polars không?
Đánh giá lười nghĩa là bạn mô tả trước những gì muốn làm và Polars sẽ chờ để chạy. Khi bạn gọi .collect(), Polars sẽ chạy tất cả bước cùng lúc theo cách tối ưu. Điều này giúp nhanh hơn vì tránh công việc thừa và giảm sử dụng bộ nhớ.
Một số kỹ thuật thao tác dữ liệu nâng cao trong Polars là gì?
Polars có thể tính trung bình động, hàm cửa sổ và gom nhóm theo thời gian cho chuỗi thời gian. Nó cũng hỗ trợ các kiểu join như as-of, semi và anti. Polars có thể xử lý dữ liệu lồng nhau với list và struct, biến đổi bảng với pivot và melt, và sử dụng các biểu thức mạnh mẽ có điều kiện.
Polars tích hợp với hệ sinh thái Python như thế nào?
Polars hoạt động tốt với các công cụ khác. Bạn có thể dễ dàng chuyển đổi dữ liệu sang pandas, NumPy hoặc Arrow để phục vụ học máy và trực quan hóa. Nó hỗ trợ đọc/ghi các định dạng như CSV, Parquet và IPC. Polars cũng chạy mượt trong Jupyter notebook và kết nối với nhiều thư viện Python.