Pandas 2.0正式版在4月3日已經釋出了,以後我們pip install預設安裝的就是2.0版了,Polars 是最近比較火的一個DataFrame 庫,最近在kaggle上經常使用,是以這裡我們将對比下 Pandas 1.5,Polars,Pandas 2.0 。看看在速度上 Pandas 2.0有沒有優勢。
Polars
Polars 是一個 Rust 和 Python 中的快速多線程 DataFrame 庫/記憶體查詢引擎。它使用 Apache Arrow作為記憶體模型在 Rust 中實作。它在2021年3月釋出。
Polars的一些主要特點如下:
- 快速:Polars在處理大型資料集時非常高效。它使用Rust編寫,利用Rust的記憶體安全和零成本抽象,可以在不犧牲性能的情況下處理大規模資料集。
- 可擴充:Polars支援并行化和分布式計算,是以可以處理非常大的資料集。它還具有可插拔的資料源接口,可以從不同的資料源讀取和寫入資料。
- 易于使用:Polars具有類似于Pandas的API,是以熟悉Pandas的使用者可以很容易地開始使用Polars。它還具有完整的文檔和示例,可幫助使用者快速入門。
- 支援多種資料類型: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流程後,根據每個過程的秒平均值,測試性能的最終結果如下表所示。
可以看到POLARS很棒
但是上面代碼是不是有問題呢?
對,還記得我們在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
裝飾器調用方法如下圖所示
完整測試結果
我們就直接來看結果了(每個測試都運作了三次):
parquet檔案提取的新腳本,最終的時間結果與前面測試類似:
CPU結果
RAM的結果
結果難以解釋,但是可以說明rust的确記憶體占用高
但是我們看到,POLARS的确還是要快一些,如果在處理時間是一個非常重要的名額的時候可以試試POLARS(但是他的CPU占用高,說明如果比較慢的CPU也不一定能獲得提高,還要具體測試),如果你不想學習POLARS的文法,那麼Pandas 2.0應該是速度很快的一個折中的選擇了。
作者:Luís Oliveira