博客 / 詳情

返回

一份寫給數據工程師的 Polars 遷移指南:將 Pandas 速度提升 20 倍代碼重構實踐

在大數據處理領域,性能和效率始終是核心問題。

polars

作為新一代數據處理框架,通過利用Rust語言的底層實現和現代化的並行計算架構,在處理大規模數據集時展現出顯著的性能優勢。根據性能測試文章的數據顯示,在CSV文件讀取操作中,

polars

的處理速度可達

pandas

的20倍。這種性能提升主要得益於其優化的內存管理機制和並行計算能力。

本文將系統地介紹如何從

pandas

遷移到

polars

,重點關注兩個框架之間的語法對應關係和最佳實踐。

📊 適用場景:

  • 處理大規模數據集的效率瓶頸
  • 需要提升數據處理性能的工程團隊
  • 想要學習現代數據處理框架的工程師
  • 正在考慮技術棧升級的技術負責人

⚡️ 核心特性:

  • 20倍的性能提升潛力
  • 更低的內存佔用
  • 完善的並行計算支持
  • 類 SQL 的聲明式語法
  • 智能的查詢優化器

1、環境配置與基礎設置

首先需要通過pip包管理器安裝必要的庫:

 # Pandas安裝
 pipinstallpandas
 
 # Polars安裝
 pipinstallpolars

在Python環境中導入這些庫:

 # Pandas導入語句
 importpandasaspd
 
 # Polars導入語句
 importpolarsaspl

推薦使用這些標準的別名(pd和pl),因為它們在數據科學社區中被廣泛採用,有助於代碼的可讀性和維護性。

2、DataFrame的創建與基礎操作

DataFrame是數據處理中的核心數據結構,代表二維表格數據:

 # Pandas中創建DataFrame
 df=pd.DataFrame({'a': [1, 1, 1], 'b': [2, 2, 2]})
 
 # Polars中創建DataFrame
 df=pl.DataFrame({'a': [1,1, 1], 'b': [2, 2, 2]})

這裏的DataFrame創建展示了兩個框架的基本語法相似性。兩者都支持通過字典構造數據,其中鍵作為列名,值作為列數據。

3、數據導入操作

數據導入是數據分析的第一步,兩個框架都提供了高效的數據讀取接口:

 # Pandas讀取CSV
 df=pd.read_csv('data.csv')
 
 # Polars讀取CSV
 df=pl.read_csv('data.csv')

Polars的CSV讀取實現了多線程並行處理,對於大型文件的讀取性能顯著優於Pandas。此外Polars還會自動推斷最優的數據類型,減少內存使用。

4、數據檢查與探索

數據探索是理解數據集特徵的關鍵步驟:

 # Pandas數據探索方法
 df.head()  # 查看前幾行數據
 df.info()  # 顯示數據基本信息
 df.describe()  # 生成描述性統計
 
 # Polars數據探索方法
 df.head()  # 查看前幾行數據
 df.schema  # 顯示數據結構信息
 df.describe()  # 生成描述性統計

Polars的schema屬性提供了更高效的數據類型查看機制,直接顯示每列的數據類型,而不需要像Pandas的info()那樣進行完整的內存統計。

5、列選擇操作

列選擇是數據處理中的基礎操作,兩個框架採用了不同的語法範式:

 # Pandas列選擇
 df['a']  # 選擇單列
 df[['a', 'b']]  # 選擇多列
 
 # Polars列選擇
 df.select('a')  # 選擇單列
 df.select(['a', 'b'])  # 選擇多列

Polars的select方法提供了更一致的API接口,可以與其他操作方法輕鬆鏈式調用。這種設計有助於構建更清晰的數據處理流程。

6、數據過濾技術

數據過濾是數據分析中的核心操作,用於根據特定條件選擇數據子集:

 # Pandas過濾操作
 df[df['a'] >2]
 
 # Polars過濾操作
 df.filter(pl.col('a') >2)

Polars的過濾語法更加明確,使用

pl.col()

顯式引用列,這種方式不僅提高了代碼的可讀性,還允許在複雜條件下更靈活的列操作。此外Polars的過濾操作在後台使用了向量化計算,提供更高的執行效率。

7、列操作與數據轉換

最基本的列操作是添加新的計算列:

 # Pandas添加列
 df['c'] =df['a'] +df['b']
 
 # Polars添加列
 df=df.with_columns((pl.col('a') +pl.col('b')).alias('c'))

Polars的

with_columns

方法提供了一個聲明式API,使操作更加清晰且可組合。

複雜的條件轉換在數據處理中很常見:

 # Pandas條件轉換
 df['b'] =df['a'].apply(lambdax: 1ifx=='high'else0ifx=='equal'else-1)
 
 # Polars條件轉換
 df=df.with_columns(
     pl.when(pl.col('a') =='high')
       .then(1)
       .when(pl.col('a') =='equal')
       .then(0)
       .otherwise(-1)
       .alias('b')
 )

Polars的條件語法更接近SQL風格,提供了更清晰的邏輯流程,並且實現了更好的性能優化。

在實際應用中,經常需要基於某些列的條件來選擇其他列的值:

 # Pandas列間條件選擇
 df['d'] =df[['a','b','c']].apply(lambdax: x['a'] ifx['c'] >0.5elsex['b'])
 
 # Polars列間條件選擇
 df=df.with_columns(
     pl.when(pl.col('c') >0.5)
       .then('a')    # 選擇列a
       .otherwise('b')  # 選擇列b
       .alias('d')
 )

8、列重命名操作

列重命名是數據預處理中的常見需求:

 # Pandas重命名
 df.rename(columns={'a': 'alpha'})
 
 # Polars重命名
 df.rename({'a': 'alpha'})

兩個框架的重命名語法相似,但Polars的實現在處理大數據集時更加高效。

9、分組聚合操作

分組操作允許我們對數據進行細粒度的分析:

 # Pandas分組求和
 df.groupby('a')['b'].sum()
 
 # Polars分組求和
 df.group_by('a').agg(pl.col('b').sum())

在實際應用中,常需要同時計算多個統計指標:

 # Pandas多指標聚合
 df.groupby('a').agg({'b': ['sum', 'mean'], 'c': 'max'})
 
 # Polars多指標聚合
 df.group_by('a').agg([
     pl.col('b').sum().alias('b_sum'),
     pl.col('b').mean().alias('b_mean'),
     pl.col('c').max().alias('c_max')
 ])

Polars的分組聚合語法更加顯式,雖然代碼量稍多,但提供了更好的類型安全性和性能優化空間。每個聚合操作都可以被單獨優化,並且支持並行計算。

分組排名計算

在數據分析中,計算組內排名是一個常見需求:

 # Pandas分組排名
 df['rank'] =df.groupby('a')['b'].rank(method='dense')
 
 # Polars分組排名
 df=df.with_columns(
     pl.col('b').rank('dense').over('a').alias('rank')
 )

Polars的語法採用了SQL風格的

over

子句,這種設計更接近標準的數據處理範式,並且在處理大規模數據集時更有效率。

分組轉換操作

對分組數據進行轉換是數據處理中的高級操作:

 # Pandas分組轉換
 df['sum_squared'] =df.groupby('a')['b'].transform(lambdax: x.sum() *2)
 
 # Polars分組轉換
 df=df.with_columns(
     (pl.col('b').sum().over('a') *2).alias('sum_squared')
 )

Polars的實現避免了使用lambda函數,提供了更直接的列操作方式,這不僅提高了代碼的可讀性,還實現了更好的性能優化。

10、時間窗口計算

滑動窗口計算在時間序列分析中極為重要:

 # Pandas滑動平均
 df['rolling_avg'] =df['b'].rolling(window=3).mean()
 
 # Polars滑動平均
 df=df.with_columns(
     pl.col('b').rolling_mean(window_size=3).alias('rolling_avg')
 )

Polars的窗口操作實現了更高效的內存管理,特別適合處理大規模時間序列數據。

11、累計統計計算

累計統計在數據分析中用於追蹤數據的演變趨勢:

 # Pandas累計統計
 df['cum_sum'] =df['b'].cumsum()
 df['cum_prod'] =df['b'].cumprod()
 df['cum_mean'] =df['b'].expanding().mean()
 
 # Polars累計統計
 df.with_columns([
     pl.col('b').cum_sum().alias('cum_sum'),
     pl.col('b').cum_prod().alias('cum_prod'),
     pl.col('b').cumulative_eval(pl.element().mean()).alias('cum_mean')
 ])

Polars提供了更統一的累計計算接口,並且支持更復雜的自定義累計操作。

12、條件聚合操作

條件聚合允許我們基於特定條件計算統計量:

 # Pandas條件聚合
 df['sum_if'] =df[df['a'] >2]['b'].sum()
 
 # Polars條件聚合
 sum_if=df.filter(pl.col('a') >2).select(pl.col('b').sum()).item()

Polars的實現更加直觀,並且通過優化的查詢計劃提供更好的性能。

13、 排序操作

數據排序是數據分析中的基礎操作:

 # Pandas排序
 df.sort_values(by='a')
 
 # Polars排序
 df.sort('a')

Polars提供了更簡潔的排序語法,同時在底層實現了更高效的排序算法。

14、空值處理

處理缺失數據是數據清洗的重要環節:

 # Pandas空值處理
 df.fillna(0)  # 填充空值
 df.dropna()   # 刪除包含空值的行
 
 # Polars空值處理
 df.fill_null(0)  # 填充空值
 df.drop_nulls()  # 刪除包含空值的行

Polars對空值的處理採用了更現代的命名方式,並且在實現上考慮了內存效率和計算性能。

15、DataFrame連接操作

數據集的連接操作是數據整合的核心技術:

 # Pandas數據連接
 df_merged=pd.merge(df1, df2, on='key', how='inner')
 
 # Polars數據連接
 df_merged=df1.join(df2, on='key', how='inner')

Polars的連接操作採用了更接近SQL的語法,並且在實現上使用了哈希連接和排序合併連接等優化技術,顯著提升了大數據集的連接性能。支持的連接類型包括:

  • inner:內連接,僅保留匹配的記錄
  • left:左連接,保留左表所有記錄
  • outer:外連接,保留所有記錄
  • cross:交叉連接,生成笛卡爾積

16、數據集合並

數據集合並用於處理來自不同源的數據:

 # Pandas數據合併
 df_concat_vert=pd.concat([df1, df2], axis=0)  # 垂直合併
 df_concat_horiz=pd.concat([df1, df2], axis=1)  # 水平合併
 
 # Polars數據合併
 df_concat_vert=pl.concat([df1, df2])  # 垂直合併
 df_concat_horiz=pl.concat([df1, df2], how='horizontal')  # 水平合併

Polars的合併操作在處理大規模數據集時表現出更好的內存效率,並且提供了更直觀的參數設置。垂直合併特別適用於處理分片數據或時間序列數據的合併。

17、數據透視表操作

數據透視表是數據分析中的重要工具,用於多維度數據彙總:

 # Pandas數據透視表
 df.pivot_table(index='a', columns='b', values='c', aggfunc='sum')
 
 # Polars數據透視表
 df.pivot(values='c', index='a', columns='b', aggregate_fn='sum')

更復雜的場景下,可能需要同時計算多個聚合指標:

 # Pandas多重聚合透視表
 df.pivot_table(index='a', columns='b', values='c', aggfunc=['sum', 'mean'])
 
 # Polars多重聚合透視表
 df.group_by(['a', 'b']).agg([
     pl.col('c').sum().alias('c_sum'),
     pl.col('c').mean().alias('c_mean')
 ]).pivot(values=['c_sum', 'c_mean'], index='a', columns='b')

Polars的實現雖然寫法較長,但提供了更靈活的聚合函數定義能力,並且在處理大規模數據集時性能更優。

18、列表類型數據展開

處理嵌套數據結構是數據預處理中的常見需求:

 # Pandas列表展開
 df=pd.DataFrame({'a': [1, 2], 'b': [[1, 2], [3, 4]]})
 df=df.explode('b')
 
 # Polars列表展開
 df=pl.DataFrame({'a': [1, 2], 'b': [[1, 2], [3, 4]]})
 df=df.explode('b')

兩個框架在這方面的語法非常相似,但Polars的實現在內存使用上更加高效,特別是在處理大型嵌套數據結構時。

19、數據導出

數據處理完成後的導出操作:

 # Pandas導出CSV
 df.to_csv('output.csv', index=False)
 
 # Polars導出CSV
 df.write_csv('output.csv')

Polars提供了多線程寫入能力,可以顯著提升大數據集的導出速度。

20、惰性求值

Polars的一個重要特性是支持惰性求值:

  • 使用lazy()方法將DataFrame轉換為LazyFrame
  • 可以構建複雜的查詢計劃而不立即執行
  • 通過collect()觸發實際計算
  • 能夠自動優化查詢計劃,提升性能

示例:

 # 惰性操作鏈
 result= (df.lazy()
           .filter(pl.col('value') >0)
           .group_by('category')
           .agg(pl.col('value').sum())
           .collect())

總結

Polars作為現代化的數據處理框架,通過先進的工程實踐和算法優化,為數據科學工作者提供了高效的數據處理工具。在從Pandas遷移時,理解這些核心概念和最佳實踐將有助於充分發揮Polars的性能優勢。

https://avoid.overfit.cn/post/c9ffc87af55f4cd494d7954c11ce384c

user avatar kinfuy 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.