天天看點

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

作者:deephub

Pandas 2.0正式版在4月3日已經釋出了,以後我們pip install預設安裝的就是2.0版了,Polars 是最近比較火的一個DataFrame 庫,最近在kaggle上經常使用,是以這裡我們将對比下 Pandas 1.5,Polars,Pandas 2.0 。看看在速度上 Pandas 2.0有沒有優勢。

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

Polars

Polars 是一個 Rust 和 Python 中的快速多線程 DataFrame 庫/記憶體查詢引擎。它使用 Apache Arrow作為記憶體模型在 Rust 中實作。它在2021年3月釋出。

Polars的一些主要特點如下:

  1. 快速:Polars在處理大型資料集時非常高效。它使用Rust編寫,利用Rust的記憶體安全和零成本抽象,可以在不犧牲性能的情況下處理大規模資料集。
  2. 可擴充:Polars支援并行化和分布式計算,是以可以處理非常大的資料集。它還具有可插拔的資料源接口,可以從不同的資料源讀取和寫入資料。
  3. 易于使用:Polars具有類似于Pandas的API,是以熟悉Pandas的使用者可以很容易地開始使用Polars。它還具有完整的文檔和示例,可幫助使用者快速入門。
  4. 支援多種資料類型:Polars支援許多常見的資料類型,包括數字,布爾值,字元串和日期時間。它還支援類似于DataFrame的表格結構,可以進行列操作和過濾等操作。

Polars的一個最大好處是,它不僅有Python的包,Nodejs,Rust等也可以友善的進行繼承使用,并且經過各方的驗證,它的确要比Pandas1.x快很多。

Pandas 2.0

在之前的文章我們已經介紹了 Pandas 2.0,“它要快得多”(還不是穩定版本)。并且它也有了Apache Arrow的後端。

現在,他的正式版釋出了,對于Pandas 2.0 的更新請看官網說明

下面我們就要開始進行簡單的測試了,我們要測試這3個庫的性能,是以需要使用一些比較大型的資料集。這裡我們使用紐約計程車資料集。

簡單ETL

從Data Talks Club下載下傳csv資料集,NYC.gov下載下傳parquet資料集。

還需要紐約市區域。

1、E 提取

把csv檔案和parquet檔案轉換為DF,測試提取的性能。

下面是pandas的

def pd_read_csv(path, engine_pd,):
"""
Converting csv file into Pandas dataframe
"""
df= pd.read_csv(path, engine=engine_pd)
return df
def pd_read_parquet(path, ):
"""
Converting parquet file into Pandas dataframe
"""
df= pd.read_parquet(path,)
return df           

這裡是Polars的

def pl_read_csv(path, ):
"""
Converting csv file into Pandas dataframe
"""
df= pl.read_csv(path,)
return df
def pl_read_parquet(path, ):
"""
Converting parquet file into Pandas dataframe
"""
df= pl.read_parquet(path,)
return df           

讀取代碼如下:

path1="yellow_tripdata_2021-01.csv.gz"
df_trips= pd_read_csv(path1, engine_pd)
path2="taxi+_zone_lookup.csv"
df_zone= pd_read_csv(path2, engine_pd)
path1="yellow_tripdata_2021-01.parquet"
df_trips= pd_read_parquet(path1,)
path2 = "taxi+_zone_lookup.csv"
df_zone = pd_read_csv(path2, engine_pd)           

2、T 轉換

為了測試,我們通過Pickup Id擷取trip_distance的均值;

過濾查詢性能是以擷取以“East”結尾的區域。

Pandas代碼:

def mean_test_speed_pd(df_pd):
"""
Getting Mean per PULocationID
"""
df_pd = df_pd[['PULocationID', 'trip_distance']]
df_pd["PULocationID_column"] = df_pd[['PULocationID']].astype(int)
df_pd=df_pd.groupby('PULocationID').mean()
return df_pd
def endwith_test_speed_pd(df_pd):
"""
Only getting Zones that end with East
"""
df_pd = df_pd[df_pd.Zone.str.endswith('East')]
return df_pd           

Polars

def mean_test_speed_pl(df_pl):
"""
Getting Mean per PULocationID
"""
df_pl = df_pl[['PULocationID', 'trip_distance']].groupby('PULocationID').mean()
return df_pl
def endwith_test_speed_pd(df_pl):
"""
Only getting Zones that end with East
"""
df_pl = df_pl.filter(pl.col("Zone").str.ends_with('East'))
return df_pl           

3、L 加載

将最終結果加載回parquet檔案,可以測試寫入性能:

pandas

def loading_into_parquet(df_pd, engine):
"""
Save dataframe in parquet
"""
df_pd.to_parquet(f'yellow_tripdata_2021-01_pd_v{pd.__version__}.parquet',engine)           

polars

def loading_into_parquet(df_pl):
"""
Save dataframe in parquet
"""
df_pl.write_parquet(f'yellow_tripdata_2021-01_pl.parquet')           

4、結果展示

運作ETL流程後,根據每個過程的秒平均值,測試性能的最終結果如下表所示。

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

可以看到POLARS很棒

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

但是上面代碼是不是有問題呢?

對,還記得我們在pandas2.0那篇文章中說過,read_csv獲得Numpy資料類型,為read_parquet獲得Pyarrow資料類型。而Polars中,當我們執行read_csv和read_parquet時,我們為所有列獲得相同的資料類型。是以我們測試的并不準确。 另外我們也沒有比較比較RAM和CPU的使用情況,是以沒有全方位的測試。

下面我們開始修複上面的問題,并添加RAM和CPU的使用情況,這樣應該算是一個比較完善的測試了。

CPU和RAM分析

我們可以使用process.memory_info()檢查每個函數之前、之後和之間的記憶體。而psutil.cpu_percent可以獲得最近2秒内的CPU。是以就有了下面的裝飾器:

import os
import psutil
def process_memory():
process = psutil.Process(os.getpid())
mem_info = process.memory_info()
return mem_info.rss
def process_cpu():
"""
Getting cpu_percent in last 2 seconds
"""
cpu_usage = psutil.cpu_percent(2)
return cpu_usage

# decorator function mem
def profile_mem(func):
def wrapper(*args, **kwargs):

mem_before = process_memory()
result = func(*args, **kwargs)
mem_after = process_memory()
print("Consumed memory: {:,}".format(
mem_before, mem_after, mem_after - mem_before))

return result
return wrapper
# decorator function cpu
def profile_cpu(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
cpu_after = process_cpu()
print(f"Consumed cpu: {cpu_after}")


return result
return wrapper           

裝飾器調用方法如下圖所示

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

完整測試結果

我們就直接來看結果了(每個測試都運作了三次):

parquet檔案提取的新腳本,最終的時間結果與前面測試類似:

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

CPU結果

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

RAM的結果

Pandas 2.0正式釋出:Pandas 1.5,Polars,Pandas 2.0 速度對比測試

結果難以解釋,但是可以說明rust的确記憶體占用高

但是我們看到,POLARS的确還是要快一些,如果在處理時間是一個非常重要的名額的時候可以試試POLARS(但是他的CPU占用高,說明如果比較慢的CPU也不一定能獲得提高,還要具體測試),如果你不想學習POLARS的文法,那麼Pandas 2.0應該是速度很快的一個折中的選擇了。

作者:Luís Oliveira

繼續閱讀