詳解Polars 多 DataFrame 合并操作全指南
從 pandas 遷移過來的人,最常問的一句話是:"concat 和 merge 在 Polars 里怎么寫?"——答案不只是"有替代品",而是"比你想象的更完整"。
一、pl.concat()—— 拼接這件事,Polars 想得很周全
pandas 的 concat 能做的,Polars 全都有;pandas 做不到的,Polars 也補上了。核心函數(shù)是 pl.concat(),通過一個 how 參數(shù)切換行為,覆蓋了從最簡單的縱向堆疊到多表對齊合并的幾乎所有場景。
函數(shù)簽名
pl.concat(
items: Iterable[DataFrame | LazyFrame | Series],
*,
how: str = 'vertical',
rechunk: bool = False,
parallel: bool = True,
)
??vertical— 最樸素的縱向堆疊
列名和類型必須完全一致,行數(shù)疊加變長。這是默認模式,也是日常用得最多的。
import polars as pl
df1 = pl.DataFrame({"a": [1], "b": [3]})
df2 = pl.DataFrame({"a": [2], "b": [4]})
result = pl.concat([df1, df2])
# shape: (2, 2)
# │ a ┆ b │
# │ 1 ┆ 3 │
# │ 2 ┆ 4 │
列名對不上會直接報錯,沒有靜默處理。
??vertical_relaxed— 類型不完全一致?自動升檔
和 vertical 邏輯相同,但遇到類型沖突時會自動提升為公共超類型,比如 Int32 遇上 Float64,結(jié)果列統(tǒng)一變成 Float64,省去手動轉(zhuǎn)換的麻煩。
df1 = pl.DataFrame({"a": [1], "b": [3]})
df2 = pl.DataFrame({"a": [2.5], "b": [4]})
result = pl.concat([df1, df2], how="vertical_relaxed")
# 列 a 自動從 i64 提升為 f64
??horizontal— 橫著拼,變寬不變長
把多個 DataFrame 的列并排擺在一起,行數(shù)不同時短的那邊用 null 補齊。列名不能重疊,否則報錯。
df_h1 = pl.DataFrame({"l1": [1, 2], "l2": [3, 4]})
df_h2 = pl.DataFrame({"r1": [5, 6, 7], "r2": [8, 9, 10]})
result = pl.concat([df_h1, df_h2], how="horizontal")
# shape: (3, 4),df_h1 的兩列用 null 補到第 3 行
??diagonal— 列結(jié)構(gòu)不同?取并集,缺的填 null
這是處理"列不對齊"場景最直接的方式。兩張表的列名取并集,各自沒有的列填 null,行數(shù)疊加。
df_d1 = pl.DataFrame({"a": [1], "b": [3]})
df_d2 = pl.DataFrame({"a": [2], "c": [4]})
result = pl.concat([df_d1, df_d2], how="diagonal")
# shape: (2, 3)
# │ a ┆ b ┆ c │
# │ 1 ┆ 3 ┆ null │
# │ 2 ┆ null ┆ 4 │
diagonal_relaxed 在此基礎(chǔ)上額外支持類型自動提升,兩者搭配基本能覆蓋絕大多數(shù)"臟數(shù)據(jù)合并"的場景。
??align系列 —— 多表按鍵對齊,一步到位 ?
這是 Polars 相對新的能力,也是最有意思的一個。它會自動識別多個 DataFrame 的公共鍵列,按鍵對齊后橫向合并——本質(zhì)上是幫你把"先 join 再 concat"這兩步合成了一步。
df_a1 = pl.DataFrame({"id": [1, 2], "x": [3, 4]})
df_a2 = pl.DataFrame({"id": [2, 3], "y": [5, 6]})
df_a3 = pl.DataFrame({"id": [1, 3], "z": [7, 8]})
pl.concat([df_a1, df_a2, df_a3], how="align")
# shape: (3, 4)
# │ id ┆ x ┆ y ┆ z │
# │ 1 ┆ 3 ┆ null ┆ 7 │
# │ 2 ┆ 4 ┆ 5 ┆ null │
# │ 3 ┆ null ┆ 6 ┆ 8 │
align 系列有四種變體,對應(yīng)不同的保留策略:
| how 參數(shù) | 等效 join 類型 |
|---|---|
| align / align_full | full outer join |
| align_left | left join |
| align_right | right join |
| align_inner | inner join |
pl.concat()全策略速查
| how 參數(shù) | 行為 | pandas 對應(yīng) | 適用場景 |
|---|---|---|---|
| vertical | 縱向堆疊,列必須一致 | concat(axis=0) | 同結(jié)構(gòu)多批數(shù)據(jù)合并 |
| vertical_relaxed | 縱向堆疊,類型自動提升 | concat(axis=0) | 類型略有差異的同結(jié)構(gòu)數(shù)據(jù) |
| horizontal | 橫向并列,列不可重疊 | concat(axis=1) | 不同特征列拼接 |
| diagonal | 取列并集,缺失填 null | concat(axis=0, join='outer') | 列結(jié)構(gòu)不同的數(shù)據(jù)合并 |
| diagonal_relaxed | 同上 + 類型提升 | 同上 | 列結(jié)構(gòu)和類型均不同 |
| align | 按公共鍵對齊橫向合并 | merge + concat | 多 df 按 key 對齊 |
二、df.join()—— 關(guān)聯(lián)合并,SQL 那套邏輯全都在
如果說 concat 是"把表擺在一起",那 join 就是"按條件把兩張表的行配對"。Polars 的 join() 覆蓋了 SQL 里幾乎所有標(biāo)準(zhǔn) join 類型,語法也比 pandas 的 merge 更簡潔。
函數(shù)簽名
df.join(
other: DataFrame,
on: str | list | None = None,
how: str = 'inner',
*,
left_on=None,
right_on=None,
suffix: str = '_right',
validate: str = 'm:m',
join_nulls: bool = False,
coalesce: bool | None = None,
)
六種 join 策略,逐一拆解
inner join(默認) — 只留兩邊都能匹配上的行,是最常見的用法。
df.join(other_df, on="ham")
left join — 左表全保留,右表沒匹配到的位置填 null。
df.join(other_df, on="ham", how="left", coalesce=True)
full join — 兩邊都全保留,互相沒匹配到的填 null。數(shù)據(jù)探查時很好用。
df.join(other_df, on="ham", how="full")
cross join — 笛卡爾積,不需要 on 參數(shù),生成所有行的兩兩組合。數(shù)據(jù)量小時偶爾有用,大表慎用。
df.join(other_df, how="cross")
semi join — 只保留左表中能在右表找到匹配的行,但不附加右表的列。本質(zhì)上是個過濾器,比先 join 再 select 列更高效。
df.join(other_df, on="ham", how="semi")
anti join — semi join 的反面,只保留左表中在右表找不到匹配的行。做數(shù)據(jù)差異比對時非常順手。
df.join(other_df, on="ham", how="anti")
幾個容易忽略的參數(shù)
| 參數(shù) | 說明 |
|---|---|
| left_on / right_on | 兩表鍵列名不同時分別指定,不必提前重命名 |
| suffix | 重名列的后綴,默認 _right,可自定義 |
| validate | 校驗關(guān)系類型:'1:1'、'1:m'、'm:1'、'm:m',數(shù)據(jù)質(zhì)量把關(guān)利器 |
| join_nulls | 是否將 null 視為相等進行匹配,默認 False |
| coalesce | 是否將兩邊的鍵列合并為一列輸出 |
validate 這個參數(shù)在生產(chǎn)環(huán)境里尤其值得打開——它能在數(shù)據(jù)出現(xiàn)意外的一對多或多對多關(guān)系時直接報錯,而不是悄悄給你生成一張膨脹的結(jié)果表。
三、進階武器:join_asof()與join_where()
join_asof()— 時序數(shù)據(jù)的專屬利器
時序場景里經(jīng)常遇到這樣的問題:兩張表的時間戳對不上,但你想找"最近的那條記錄"。join_asof() 就是為此而生的,邏輯類似 left join,但匹配的是最近的鍵值而非精確相等。兩表必須提前按鍵列排好序。
df.join_asof(
other,
on="timestamp",
strategy="backward", # 'backward'(默認) | 'forward' | 'nearest'
tolerance="1d", # 超出容差范圍則不匹配
by="stock_id", # 先按此列分組,再做 asof join
)
三種匹配策略的含義直白明了:
- backward:找右表中 ≤ 左表時間戳的最近一行
- forward:找右表中 ≥ 左表時間戳的最近一行
- nearest:找距離最近的那行,不管方向
tolerance 支持?jǐn)?shù)值,也支持時間字符串,比如 "3d12h4m25s" 這樣的寫法,處理金融或日志數(shù)據(jù)時相當(dāng)省心。
join_where()— 非等值條件匹配
標(biāo)準(zhǔn) join 只能做等值匹配,但現(xiàn)實中經(jīng)常需要"價格在某個區(qū)間內(nèi)""日期晚于某個時間點"這類條件。join_where() 接受任意謂詞表達式,找出所有滿足條件的行對組合。
df.join_where(
other,
pl.col("price_left") >= pl.col("price_min"),
pl.col("price_left") <= pl.col("price_max"),
)
pandas 里沒有直接對應(yīng)的方法,通常要繞道 merge 加 query 或者手寫循環(huán),Polars 把這個場景單獨封裝成一個函數(shù),思路很清晰。
四、Polars vs pandas 對照速查
從 pandas 遷移過來,下面這張表應(yīng)該能省不少查文檔的時間:
| 需求場景 | pandas 寫法 | Polars 寫法 |
|---|---|---|
| 縱向堆疊(同結(jié)構(gòu)) | pd.concat([df1,df2]) | pl.concat([df1,df2]) |
| 縱向堆疊(列不同) | pd.concat([df1,df2], join='outer') | pl.concat([df1,df2], how="diagonal") |
| 橫向拼接 | pd.concat([df1,df2], axis=1) | pl.concat([df1,df2], how="horizontal") |
| inner join | pd.merge(df1,df2,on='key') | df1.join(df2, on='key') |
| left join | pd.merge(...,how='left') | df1.join(df2, on='key', how='left') |
| full outer join | pd.merge(...,how='outer') | df1.join(df2, on='key', how='full') |
| 時序近似匹配 | pd.merge_asof(...) | df1.join_asof(df2, on='ts') |
| 非等值條件匹配 | 無直接對應(yīng) | df1.join_where(df2, 條件表達式) |
五、選哪個?幾條實用判斷原則
多批同結(jié)構(gòu)數(shù)據(jù)合并,直接用 pl.concat([...]) 默認的 vertical 模式,性能極高,沒有懸念。
列結(jié)構(gòu)不統(tǒng)一,用 diagonal 或 diagonal_relaxed,自動補 null,不用提前對齊列名。
按鍵關(guān)聯(lián)兩表,用 df.join(),記得打開 validate 參數(shù)做數(shù)據(jù)質(zhì)量校驗,生產(chǎn)環(huán)境里這一步能幫你擋掉很多隱患。
時序數(shù)據(jù)對齊,join_asof() 是專門為此設(shè)計的,配合 tolerance 參數(shù)避免匹配到過遠的記錄。
LazyFrame 場景,pl.concat() 的 parallel=True 參數(shù)可以并行執(zhí)行多個懶計算,大數(shù)據(jù)量下性能優(yōu)勢會更明顯。
到此這篇關(guān)于詳解Polars 多 DataFrame 合并操作全指南的文章就介紹到這了,更多相關(guān)Polars 多 DataFrame 合并內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于keras中keras.layers.merge的用法說明
這篇文章主要介紹了關(guān)于keras中keras.layers.merge的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05
Python+Paramiko編寫簡單的SFTP文件上傳下載工具類
Paramiko 是 Python 中最流行的 SSH2 協(xié)議實現(xiàn)庫,基于它我們可以輕松實現(xiàn) SFTP 客戶端功能,本文將分享一個封裝好的 SftpClient 類,支持文件上傳、下載,感興趣的小伙伴可以了解下2026-01-01
創(chuàng)建pycharm的自定義python模板方法
今天小編就為大家分享一篇創(chuàng)建pycharm的自定義python模板方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
Python之Matplotlib繪圖調(diào)節(jié)清晰度解決方案
Matplotlib是一個Python的繪圖庫,可以用來繪制各種類型的圖表,包括線圖、散點圖、柱狀圖等等,這篇文章主要給大家介紹了關(guān)于Python之Matplotlib繪圖調(diào)節(jié)清晰度的相關(guān)資料,需要的朋友可以參考下2024-03-03

