+3

Pandas 2.0 có gì mới?

Mayfest2023 ContentCreator

Xin chào các bạn Pandas cũng đã cập nhật lên bản 2.0 một thời gian rồi, ở bài viết này mình sẽ viết bài review xem có khác biệt gì với version cũ không nhé. Ok chúng ta cùng bắt đầu thôi nào...

Upgrade pandas 2.0

Việc đầu tiên chúng ta cần làm là update lên pandas 2.0

pip install --upgrade pandas

Nâng cao hiệu suất

Pandas 2.0 cải thiện hiệu suất, fixbug và hoạt động hiệu quả hơn. Dựa vào việc sủ dụng Apacge Arrow - một nền tảng phát triển đa ngôn ngữ, mã nguồn mở dành cho dữ liệu trong bộ nhớ. Nó được phát triển để biểu diễn dữ liệu trong bộ nhớ dạng cột, một định dạng lưu trữ và xử lý dữ liệu phổ biến trong nhiều hệ thống dữ liệu mở rộng.

Pandas 2.0 có tốc độ nhanh hơn và có thể tương tác hơn, đồng thời hỗ trợ nhiều loại dữ liệu hơn, đặc biệt là đối với các chuỗi.

import timeit
import pandas as pd
import polars as pl
import duckdb
import dask.dataframe as dd

# Prepare data
data = pd.DataFrame({
    'A': list(range(1000000)),
    'B': list(range(1000000, 2000000))
})

# Pandas 2.0
def pandas_operation():
    return data.groupby('A').sum()

pandas_time = timeit.timeit(pandas_operation, number=10)

# Polars
polars_data = pl.from_pandas(data)

def polars_operation():
    return polars_data.groupby('A').agg(pl.col('B').sum())

polars_time = timeit.timeit(polars_operation, number=10)

# DuckDB
duckdb_conn = duckdb.connect(database=':memory:', read_only=False)
duckdb_conn.register('data', data)
duckdb_cursor = duckdb_conn.cursor()

def duckdb_operation():
    duckdb_cursor.execute('SELECT A, SUM(B) FROM data GROUP BY A')
    return duckdb_cursor.fetchall()

duckdb_time = timeit.timeit(duckdb_operation, number=10)

# Dask
dask_data = dd.from_pandas(data, npartitions=4)

def dask_operation():
    return dask_data.groupby('A').sum().compute()

dask_time = timeit.timeit(dask_operation, number=10)

# Print results
print(f"Pandas 2.0: {pandas_time:.5f} seconds")
print(f"Polars: {polars_time:.5f} seconds")
print(f"DuckDB: {duckdb_time:.5f} seconds")
print(f"Dask: {dask_time:.5f} seconds")

# Output:
# Pandas 2.0: 0.98126 seconds
# Polars: 0.86279 seconds
# DuckDB: 17.13312 seconds
# Dask: 1.29167 seconds

Đoạn code này trình bày cách đánh giá hiệu suất của các tác vụ thao tác dữ liệu khác nhau trên Pandas 2.0, Polars, DuckDB và Dask, chúng ta có thể thấy Pandas 2.0 nhanh hơn đáng kể.

Cải thiện hỗ trợ cho dữ liệu Time-series

Với Pandas 1. thì việc xử lý dữ liệu chuỗi thời gian khá là rắc rối và tốn thời gian, tuy nhiên, Pandas 2.0 hỗ trợ nhiều độ phân giải khác, bao gồm mili giây, micro giây và giây. Cải tiến này mở rộng phạm vi được đề cập ở trên thêm +/-2,9e¹¹ năm! Pandas 2.0 cho phép bạn chuyển một ngày tùy ý tới hàm tạo Dấu thời gian mà không gây ra lỗi (không giống như các phiên bản trước), bất kể đơn vị thời gian đã chỉ định.

Ví dụ

Input [0]: pd.Timestamp(“1567-11-10”, unit = “s”)
Output [0]: Timestamp(‘1567-11-10 00:00:00’)

Ở đây, việc chỉ định đơn vị “s” chỉ ra rằng dấu thời gian trả về kết quả đầu ra đến giây.

Giới thiệu về các kiểu dữ liệu Nullable

Pandas 2.0 cải thiện đáng kể các loại dữ liệu nullable. Các kiểu dữ liệu có thể rỗng cho phép bạn gán một giá trị 'NULL' duy nhất cho biến thay vì các giá trị điển hình cho kiểu dữ liệu cụ thể đó. Việc chọn các loại dữ liệu có thể vô hiệu hóa sẽ dễ dàng hơn bằng cách thêm một từ khóa mới, dtype_backend. Từ khóa này trả về một DataFrame với các loại dữ liệu có thể null khi được đặt thành “numpy_nullable” cho hầu hết các chức năng I/O. Khi được sử dụng với kiểu dữ liệu đối tượng, tùy chọn này cũng có thể trả về một DataFrame với pandas StringDtype.

import pandas as pd
import io

# New sample data
new_sample_data = io.StringIO("""Category,Value,Flag,Label,Count,Rating,Percentage,Status,Code
    Fruit,100,True,Apple,25,4.5,0.50,InStock,A1
    Vegetable,200,False,Carrot,30,3.8,0.35,OutOfStock,B2
    Grain,150,True,Rice,20,4.2,0.25,InStock,C3
""")

# Reading CSV with pandas-backed nullable dtypes
data_frame = pd.read_csv(new_sample_data)

# Converting numeric columns to nullable dtypes
data_frame = data_frame.apply(pd.to_numeric, errors="ignore")

# Save the DataFrame as a Parquet file
data_frame.to_parquet("data_frame.parquet", engine="pyarrow")

# Read the Parquet file into a DataFrame
data_frame_from_parquet = pd.read_parquet("data_frame.parquet", engine="pyarrow")

Đoạn code này minh họa việc đọc tệp CSV có dữ liệu mẫu, chuyển đổi các cột số thành các loại dữ liệu có thể vô hiệu, đồng thời lưu và đọc dữ liệu dưới dạng tệp Parquet bằng công cụ pyarrow.

Cải tiến Copy-on-Write

Copy-on-Write lần đầu tiên được giới thiệu trong Pandas 1.5.0 và phiên bản 2.0 mang đến nhiều cải tiến hơn nữa. Cơ chế này giúp quản lý bộ nhớ hiệu quả hơn bằng cách trì hoãn các bản sao dữ liệu thực tế cho đến khi dữ liệu của một đối tượng được sửa đổi, giảm chi phí bộ nhớ và cải thiện hiệu suất.

Bằng cách kích hoạt Copy-on-Write, Pandas có thể tránh tạo các bản sao phòng thủ khi thực hiện các hoạt động khác nhau và thay vào đó, nó chỉ tạo các bản sao khi cần thiết, điều này dẫn đến việc sử dụng bộ nhớ hiệu quả hơn.

Và chúng ta phải set option này mỗi khi cần dùng

pd.set_option("mode.copy_on_write", True)

Ok chúng ta sẽ thử tạo một DataFrame có tên là df1 và tạo một bản sao của nó có tên là df2. Khisửa đổi cột "a" trong df2, dữ liệu cơ bản sẽ được sao chép nhưng các cột chưa sửa đổi vẫn chia sẻ cùng một bộ nhớ. Điều này dẫn đến giảm chi phí bộ nhớ và cải thiện hiệu suất.

import pandas as pd

pd.options.mode.copy_on_write = True

data = {"a": [1, 2, 3], "b": [4.0, 5.0, 6.0], "c": ["x", "y", "z"]}
df1 = pd.DataFrame(data)
df2 = df1.copy()

df2["a"] = [7, 8, 9]

print(df1)
print(df2)

Kết luận

Cảm ơn mọi người đã đọc bài viết của mình, mong nhận được sự góp ý của mọi người ạ.

Reference

https://www.shakudo.io/blog/pandas-2-upgrade-and-adapt-guide

https://pandas.pydata.org/docs/dev/whatsnew/v2.0.0.html


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí