Courses
Nếu bạn thường xuyên dùng Python để phân tích dữ liệu như tôi, bạn sẽ sớm nhận ra đọc tệp CSV là một trong những tác vụ phổ biến nhất. Tuy nhiên, khi bộ dữ liệu ngày càng lớn, cách làm này có thể trở nên chậm hoặc tốn bộ nhớ.
Polars là thư viện DataFrame hiện đại, tốc độ cao cho Python, được thiết kế như một lựa chọn hiệu năng cao thay thế cho Pandas. Nhờ tập trung vào tốc độ và mức sử dụng bộ nhớ thấp, Polars xử lý các bộ dữ liệu lớn trơn tru hơn nhiều so với các công cụ truyền thống.
Hàm cốt lõi pl.read_csv() của Polars cung cấp giải pháp đơn giản để nạp tệp CSV vào DataFrame, với các tùy chọn tích hợp để kiểm soát việc phân tích cú pháp, kiểu dữ liệu và mức sử dụng bộ nhớ.
Trong hướng dẫn này, tôi sẽ chỉ bạn cách đọc tệp CSV, kiểm soát việc phân tích và xử lý bộ dữ liệu lớn bằng hàm pl.read_csv() của Polars. Nếu bạn mới bắt đầu, hãy xem khóa học Giới thiệu về Polars của chúng tôi để học cách thao tác dữ liệu và khai thác insight với Polars.
Cách dùng cơ bản của pl.read_csv()
Trước khi đi xa hơn, hãy xem hướng dẫn Python Polars để thiết lập môi trường của bạn.
Giờ hãy xem hàm pl.read_csv() hoạt động như thế nào:
# import the module
import polars as pl
# Load CSV into a Polars DataFrame
fuel_data = pl.read_csv("Fuel_Consumption_2000-2022.csv")
# Preview first few rows
print(fuel_data.head())
Trong ví dụ trên, Polars đọc tệp và nạp vào DataFrame. Hàm trả về một Polars DataFrame, là cấu trúc dữ liệu dạng bảng, tương tự như những gì bạn nhận được trong pandas.
Mặc định, pl.read_csv():
-
Giả định hàng đầu chứa tên cột (
has_header=True) -
Tự động suy luận kiểu dữ liệu của cột
-
Dùng dấu phẩy (
,) làm dấu tách -
Đọc toàn bộ tệp vào bộ nhớ
Các tham số thường dùng trong pl.read_csv()
Giờ bạn đã biết pl.read_csv() nạp dữ liệu ra sao, hãy xem cách dùng các tham số sau để điều chỉnh cách Polars phân tích dữ liệu của bạn.
Đường dẫn tệp và nguồn dữ liệu
Polars cho phép bạn nạp dữ liệu từ nhiều nguồn khác nhau. Bạn có thể truyền đường dẫn cục bộ dạng chuỗi, đối tượng Pathlib, hoặc thậm chí là URL. Ví dụ dưới đây đọc một tệp csv lớn từ web chứa GDP của các quốc gia qua nhiều năm.
# Reading from a URL
url = "https://raw.githubusercontent.com/datasets/gdp/master/data/gdp.csv"
gdp_data = pl.read_csv(url)
Dấu tách và ký tự phân cách
Không phải mọi tệp CSV đều dùng dấu phẩy. Bạn có thể dùng đối số separator để xử lý tab, dấu chấm phẩy, dấu gạch dọc hoặc ký tự khác. Ví dụ dưới đây cho thấy cách chỉ định dấu phân tách khi đọc tệp
# Reading a Semicolon-separated file
sales_data = pl.read_csv("2024_sales.csv", separator=";")
# Reading a Tab-separated file (TSV)
orders_data = pl.read_csv("all_orders.tsv", separator="\t")
Xử lý header
Như đã thấy, Polars giả định hàng đầu của dữ liệu chứa tên cột. Nếu tệp của bạn không có hàng tiêu đề, hãy dùng tham số has_header=False như bên dưới. Polars sẽ tự gán tên cột như column_1, column_2, column_3, v.v.
# Load file without a header
orders_data = pl.read_csv("all_orders.csv", has_header=False)
Bạn cũng có thể đổi tên cột bằng cách cung cấp chính xác tên cột. Ví dụ:
# Providing specific column names
sales_data = pl.read_csv("sales_April.csv", new_columns=[
"OrderDate", "OrderNumber", "ProductKey", "SalespersonKey", "Salesperson"])
Bảng mã ký tự
Các tệp CSV khác nhau có thể dùng bảng mã văn bản khác nhau. Nếu bạn gặp ký tự lạ hoặc lỗi, hãy chỉ định encoding:
# Load CSV into a Polars DataFrame
fuel_data = pl.read_csv("Fuel_Consumption_2000-2022.csv", encoding="utf8")
Các tùy chọn encoding phổ biến khác gồm ”latin1” và ”utf8-lossy”, giúp xử lý ký tự không hợp lệ một cách phù hợp.
Cách chọn cột khi đọc CSV trong Polars
Khi làm việc với tệp CSV lớn, bạn thường không cần mọi cột. Polars cho phép chỉ nạp các cột bạn cần bằng tham số columns.
# Load only specific columns
fuel_data = pl.read_csv("Fuel_Consumption_2000-2022.csv",
columns=["YEAR", "MAKE", "MODEL"]
)
Khi bạn chọn trước các cột cần thiết lúc nạp tệp, bộ nhớ sẽ được tiết kiệm vì không tải dữ liệu thừa. Cách này cũng tăng tốc độ đọc tệp và cải thiện hiệu năng tổng thể của pipeline.
Cách xử lý kiểu dữ liệu (Schema) trong CSV của Polars
Polars là thư viện kiểu mạnh, nghĩa là mỗi cột phải có kiểu dữ liệu nhất quán, như toàn số nguyên hoặc toàn chuỗi.
Suy luận kiểu tự động
Mặc định, Polars kiểm tra dữ liệu và tự động xác định kiểu cột. Cách mặc định hoạt động tốt trong hầu hết trường hợp nhưng đôi khi có thể diễn giải sai, chẳng hạn xem ID là số nguyên thay vì chuỗi.
Chỉ định schema thủ công
Khi bạn muốn tính nhất quán trong DataFrame, bạn nên chỉ định schema dữ liệu thủ công. Điều này đảm bảo tính nhất quán giữa nhiều tệp và giúp tránh lỗi liên quan đến kiểu dữ liệu trong các bước xử lý về sau.
Trong đa số trường hợp, dùng schema_overrides để chỉ định kiểu dữ liệu cho một số cột cụ thể, đồng thời cho phép Polars suy luận các cột còn lại
import polars as pl
# Manually overriding specific data types
empl_data = pl.read_csv(
"all_employees.csv",
schema_overrides={
"id": pl.Int64,
"name": pl.String,
"age": pl.Int64,
"salary": pl.Float64
}
)
Hoặc dùng schema để định nghĩa toàn bộ cấu trúc của DataFrame.
# Manually define the full schema
empl_data = pl.read_csv(
"all_employees.csv",
schema={
"id": pl.Int64,
"name": pl.String,
"age": pl.Int64,
"salary": pl.Float64
}
)
Cách xử lý giá trị khuyết trong CSV của Polars
Mặc định, Polars tự động phát hiện các giá trị khuyết và biểu diễn chúng là null. Đôi khi các giá trị khuyết được thể hiện bằng chuỗi cụ thể, như ”NA”, ”N/A” hoặc ”missing”. Bạn có thể định nghĩa chúng bằng null_values để xử lý như null.
# Treating "N/A" and "EMPTY" as nulls
survey_data = pl.read_csv(
"survey_results.csv",
null_values=["N/A", "EMPTY", "null"]
)
Khi xử lý đúng giá trị khuyết, bạn đảm bảo kiểu dữ liệu nhất quán và ngăn tính toán sai, giảm lỗi trong quá trình phân tích và mô hình hóa.
Đọc tệp CSV lớn trong Polars
Khi làm việc với các bộ dữ liệu lớn vượt quá RAM sẵn có, Polars thật sự tỏa sáng nhờ xử lý dữ liệu mà không cần tải toàn bộ tệp cùng lúc.
Tải lười với scan_csv()
Thay vì nạp dữ liệu ngay vào bộ nhớ như read_csv(), Polars cung cấp lựa chọn tải lười, scan_csv(), xây dựng kế hoạch truy vấn tối ưu và chỉ thực thi các thao tác cần thiết.
Trong ví dụ dưới, pl.scan_csv quét tệp CSV mà không tải lên, xây dựng truy vấn chỉ lấy các cột “YEAR”, “MAKE” và “MODEL” nơi hãng xe là “ACURA”, rồi thực thi truy vấn đó. Hành động này chỉ tải phần dữ liệu đã lọc vào bộ nhớ, thay vì toàn bộ tệp.
# Lazily reference the file (no data loaded yet)
fuel_consumption = pl.scan_csv("Fuel_Consumption_2000-2022.csv")
fuel_consumption_filtered = fuel_consumption.select(
["YEAR", "MAKE", "MODEL"]).filter(pl.col("MAKE") == "ACURA")
# Execute the query and load only the required data
fuel_consumption_acura = fuel_consumption_filtered.collect()
Tôi khuyên bạn dùng scan_csv() khi:
- Làm việc với tệp lớn không thể nạp thoải mái vào bộ nhớ
- Áp dụng nhiều phép biến đổi như lọc, chọn và tổng hợp dữ liệu
- Bạn muốn tối ưu truy vấn trước khi thực thi
Streaming và hiệu quả bộ nhớ
Polars cũng cho phép streaming xử lý dữ liệu theo từng phần, giữ mức đỉnh bộ nhớ ổn định bất kể kích thước tệp.
Với tệp CSV lớn, hãy bắt đầu với scan_csv() để tạo truy vấn lười. Tệp chưa được nạp đầy đủ khi gọi scan_csv().
# Read data in chunks
fuel_consumption = pl.scan_csv("Fuel_Consumption_2000-2022.csv",
low_memory=True)
Vì cách trên vẫn dùng read_csv, cách tốt nhất là kết hợp thực thi lười với streaming.
Trong ví dụ dưới, Polars xử lý tệp theo pipeline, từng lô theo từng hàng, chỉ giữ các hàng đã lọc (nơi “CYLINDERS” > 3) trong bộ nhớ tại bất kỳ thời điểm nào.
# Lazily reference the file (no data loaded yet)
fuel_consumption = pl.scan_csv("Fuel_Consumption_2000-2022.csv")
result = fuel_consumption.filter(pl.col("CYLINDERS") > 3)
# Stream execution instead of loading everything at once
fuel_consumption_high = result.collect(engine="streaming")
Ưu thế hiệu năng so với Pandas
So với pandas, Polars thường cho hiệu năng tốt hơn khi đọc và xử lý CSV, như chúng ta sẽ thấy ở phần tiếp theo.
Polars read_csv vs Pandas read_csv
Bảng dưới tóm tắt sự khác biệt giữa Polars và Pandas khi đọc csv trong Python.
|
Khía cạnh |
Polars |
Pandas |
|
Tốc độ |
Nhanh hơn nhờ đa luồng và phân tích cú pháp tối ưu |
Chậm hơn với tệp lớn (chủ yếu đơn luồng) |
|
Sử dụng bộ nhớ |
Dấu chân bộ nhớ thấp; hỗ trợ lazy + streaming |
Tải toàn bộ dữ liệu vào bộ nhớ theo kiểu eager |
|
Cú pháp |
|
|
|
Mô hình thực thi |
Hỗ trợ thực thi lười ( |
Chỉ thực thi eager (tức thời) |
|
Tối ưu hóa |
Tối ưu truy vấn tích hợp (chiếu cột, lọc) |
Tự động tối ưu hóa hạn chế |
|
Tình huống phù hợp nhất |
Bộ dữ liệu lớn, quy trình yêu cầu hiệu năng cao |
Bộ dữ liệu nhỏ hơn, phân tích nhanh |
Tôi khuyên bạn đọc bài viết của chúng tôi về sự khác biệt giữa Pandas và Polars để xác định công cụ nào phù hợp nhất với nhu cầu phân tích của bạn.
Đọc CSV từ các nguồn khác nhau
Như đã thấy, bạn có thể dùng Polars để đọc tệp csv từ nhiều nguồn. Từ các ví dụ trên, tôi đã chỉ cách đọc csv từ tệp cục bộ và URL.
Ngoài ra, Polars có thể tự động xử lý các tệp CSV nén. Ví dụ dưới đây đọc dữ liệu từ tệp .gzip.
# Read gzip-compressed CSV
census_data = pl.read_csv("2018_census.csv.gz")
Lỗi thường gặp và cách khắc phục
Ngay cả với engine hiệu năng cao như Polars, bạn vẫn có thể gặp một số vấn đề, đặc biệt khi đọc tệp csv. Dưới đây là một số vấn đề thường gặp tôi đã gặp phải và cách khắc phục.
-
Lỗi mã hóa: Bạn có thể thấy lỗi như
UnicodeDecodeError, nghĩa là tệp không dùng mã hóa UTF-8, vấn đề thường gặp với tệp cũ hoặc CSV xuất từ một số phiên bản Excel. Để khắc phục, hãy đặt encoding phù hợp hoặc dùng“utf8-lossy”nếu tệp có ký tự không đồng nhất hoặc hỏng. -
Vấn đề dấu phân tách: Nếu DataFrame được nạp nhưng tất cả dữ liệu dồn vào một cột, nghĩa là Polars không nhận ra dấu phân tách. Để giải quyết, hãy chỉ định rõ dấu phân tách đúng bằng đối số
separator, như dấu chấm phẩy (;), tab (\t) hoặc gạch dọc (|). -
Kiểu dữ liệu không chính xác: Đôi khi Polars có thể suy luận sai kiểu cột, chẳng hạn đọc ID dạng số thành chuỗi hoặc gặp lỗi phân tích. Khi đó, bạn có thể dùng
schema_overridesđể chỉ định kiểu dữ liệu cho các cột cụ thể. Nếu muốn định nghĩa kiểu cho mọi cột, hãy dùngschema. Bạn cũng có thể tănginfer_schema_lengthđể Polars xem xét nhiều hàng hơn trước khi suy luận schema. -
Vấn đề bộ nhớ với tệp lớn: Nếu tiến trình Python bị sập khi tải tệp lớn, nghĩa là bạn đã cạn RAM. Để khắc phục, hãy chuyển từ
read_csv()sangscan_csv()để tải lười, giảm sử dụng bộ nhớ và cải thiện hiệu năng. Bạn cũng có thể nạp ít cột hơn hoặc dùng thực thi dạng streaming để tải dữ liệu theo từng phần.
Kết luận
Hàm read_csv() trong Polars dễ dùng nhưng đủ mạnh cho các tác vụ thực tế. Theo tôi, Polars có ưu thế rõ rệt khi làm việc với bộ dữ liệu ngày càng lớn.
Bước tiếp theo, hãy xem blog về engine GPU của Polars để tìm hiểu thêm các ứng dụng. Nếu bạn sẵn sàng thực hành, hãy tham gia Super Bowl Analytics with Polars để giải các bài toán phân tích thực tế, áp dụng phép tính và vận dụng kỹ thuật ML cơ bản cho các vấn đề phân tích thể thao.
Câu hỏi thường gặp
Sự khác biệt giữa read_csv() và scan_csv() trong Polars là gì?
read_csv() nạp dữ liệu eager vào bộ nhớ, trong khi scan_csv() dùng thực thi lười và chỉ xử lý dữ liệu khi bạn gọi .collect().
Khi nào tôi nên dùng scan_csv() thay vì read_csv()?
Dùng scan_csv() cho bộ dữ liệu lớn hoặc khi xâu chuỗi các phép biến đổi, vì nó tối ưu thực thi và giảm sử dụng bộ nhớ.
Polars có thể chỉ đọc các cột cụ thể từ tệp CSV không?
Có, hãy dùng tham số columns=[...] trong read_csv() hoặc chọn cột trong truy vấn lười với scan_csv().
Tôi xử lý giá trị khuyết trong tệp CSV của Polars như thế nào?
Polars mặc định coi giá trị rỗng là null, và bạn có thể định nghĩa các ký hiệu null tùy chỉnh bằng null_values=.
Polars có hỗ trợ tệp CSV nén không?
Có, Polars có thể đọc các định dạng nén như .gz và .zip mà không cần giải nén thủ công.
