Pandas 合並,連接,連接和比較


 

在連接/合並類型操作的情況下,pandas提供了各種功能,可以輕松地將Series或DataFrame與各種用於索引和關系代數功能的集合邏輯組合在一起。

此外,pandas還提供實用程序來比較兩個Series或DataFrame並總結它們之間的差異。

拼接對象

concat()函數(在pandas主命名空間中)在執行沿軸的串聯操作的所有繁重工作,同時在其他軸上執行索引(如果有)的可選設置邏輯(聯合或交集)。請注意,我之所以說“如果有”,是因為Series只有一個可能的串聯軸。

在深入探討其所有細節及其功能之前concat,這里有一個簡單的示例:

In [1]: df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],  ...: 'B': ['B0', 'B1', 'B2', 'B3'],  ...: 'C': ['C0', 'C1', 'C2', 'C3'],  ...: 'D': ['D0', 'D1', 'D2', 'D3']},  ...: index=[0, 1, 2, 3])  ...: In [2]: df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],  ...: 'B': ['B4', 'B5', 'B6', 'B7'],  ...: 'C': ['C4', 'C5', 'C6', 'C7'],  ...: 'D': ['D4', 'D5', 'D6', 'D7']},  ...: index=[4, 5, 6, 7])  ...: In [3]: df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],  ...: 'B': ['B8', 'B9', 'B10', 'B11'],  ...: 'C': ['C8', 'C9', 'C10', 'C11'],  ...: 'D': ['D8', 'D9', 'D10', 'D11']},  ...: index=[8, 9, 10, 11])  ...: In [4]: frames = [df1, df2, df3] In [5]: result = pd.concat(frames) 
 
../_images/merging_concat_basic.png

與其在ndarrays上的同級函數一樣numpy.concatenate,,pandas.concat 獲取同類類型對象的列表或字典,並將它們與“對其他軸的操作”的一些可配置處理進行連接:

pd.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, copy=True) 
  • objs:Series或DataFrame對象的序列或映射。如果傳遞了dict,則排序的鍵將用作keys參數,除非傳遞了dict ,在這種情況下,將選擇值(請參見下文)。除非所有對象都為None,否則所有None對象都將被靜默刪除,在這種情況下將引發ValueError。

  • axis :{0,1,…},默認值為0。要沿其連接的軸。

  • join:{'inner','outer'},默認為'outer'。如何處理其他軸上的索引。外部為聯合,內部為交叉。

  • ignore_index:布爾值,默認為False。如果為True,則不要在串聯軸上使用索引值。結果軸將標記為0,…,n-1。如果要串聯對象時,串聯軸沒有有意義的索引信息,這將很有用。請注意,聯接中仍會考慮其他軸上的索引值。

  • keys:序列,默認為無。使用傳遞的鍵作為最外層級別來構造層次結構索引。如果通過了多個級別,則應包含元組。

  • levels:序列列表,默認為無。用於構造MultiIndex的特定級別(唯一值)。否則,將從按鍵推斷出它們。

  • names:列表,默認為無。生成的層次結構索引中的級別的名稱。

  • verify_integrity:布爾值,默認為False。檢查新的串聯軸是否包含重復項。相對於實際數據串聯而言,這可能非常昂貴。

  • copy:布爾值,默認為True。如果為False,則不要不必要地復制數據。

沒有一點上下文,這些論點中的許多就沒有多大意義。讓我們回顧一下上面的例子。假設我們想將特定的鍵與切碎的DataFrame的每個片段相關聯。我們可以使用keys參數來做到這一點 

In [6]: result = pd.concat(frames, keys=['x', 'y', 'z']) 
 
../_images/merging_concat_keys.png

如您所見(如果您已經閱讀了文檔的其余部分),結果對象的索引具有層次結構索引這意味着我們現在可以通過鍵選擇每個塊:

In [7]: result.loc['y'] Out[7]:   A B C D 4 A4 B4 C4 D4 5 A5 B5 C5 D5 6 A6 B6 C6 D6 7 A7 B7 C7 D7 

看到這如何非常有用並不是一件容易的事。有關此功能的更多詳細信息,請參見下文。

注意

值得注意的是concat()(並因此 append())制作了數據的完整副本,並且不斷地重用此功能可能會嚴重影響性能。如果需要對多個數據集使用該操作,請使用列表推導。

frames = [ process_your_file(f) for f in files ] result = pd.concat(frames) 

在其他軸組邏輯

將多個DataFrame粘合在一起時,可以選擇如何處理其他軸(而不是串聯的軸)。這可以通過以下兩種方式完成:

  • 把它們全部結合起來join='outer'這是默認選項,因為它導致零信息丟失。

  • 以十字路口為准join='inner'

這是每種方法的一個示例。一,默認join='outer' 行為:

In [8]: df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],  ...: 'D': ['D2', 'D3', 'D6', 'D7'],  ...: 'F': ['F2', 'F3', 'F6', 'F7']},  ...: index=[2, 3, 6, 7])  ...: In [9]: result = pd.concat([df1, df4], axis=1, sort=False) 
 
../_images/merging_concat_axis1.png

警告

在版本0.23.0中更改。

默認行為join='outer'是對其他軸排序(在這種情況下為列)。在未來版本的熊貓中,默認設置為不排序。我們指定sort=False現在選擇加入新行為。

這是同一件事join='inner'

In [10]: result = pd.concat([df1, df4], axis=1, join='inner') 
 
../_images/merging_concat_axis1_inner.png

最后,假設我們只是想重用原始DataFrame中確切索引

In [11]: result = pd.concat([df1, df4], axis=1).reindex(df1.index) 

同樣,我們可以在連接之前建立索引:

In [12]: pd.concat([df1, df4.reindex(df1.index)], axis=1) Out[12]:   A B C D B D F 0 A0 B0 C0 D0 NaN NaN NaN 1 A1 B1 C1 D1 NaN NaN NaN 2 A2 B2 C2 D2 B2 D2 F2 3 A3 B3 C3 D3 B3 D3 F3 
 
../_images/merging_concat_axis1_join_axes.png

使用串聯append

一個有用的快捷方式concat()append() 在實例方法SeriesDataFrame這些方法實際上早於 concat它們串聯在一起axis=0,即索引:

In [13]: result = df1.append(df2) 
 
../_images/merging_append1.png

對於DataFrame,索引必須是不相交的,但列不必是:

In [14]: result = df1.append(df4, sort=False) 
 
../_images/merging_append2.png

append 可能需要多個對象來串聯:

In [15]: result = df1.append([df2, df3]) 
 
../_images/merging_append3.png

注意

append()追加到原始列表並返回方法不同Noneappend() 這里的方法不會修改 df1並返回帶有df2追加內容的副本

忽略串聯軸上的索引

對於DataFrame沒有有意義索引的對象,您可能希望追加它們,而忽略它們可能具有重疊索引的事實。為此,請使用ignore_index參數:

In [16]: result = pd.concat([df1, df4], ignore_index=True, sort=False) 
 
../_images/merging_concat_ignore_index.png

這也是有效的參數DataFrame.append()

In [17]: result = df1.append(df4, ignore_index=True, sort=False) 
 
../_images/merging_append_ignore_index.png

與混合ndim串聯

您可以將Series混合在一起DataFrame該 Series會轉化為DataFrame與列名的名稱Series

In [18]: s1 = pd.Series(['X0', 'X1', 'X2', 'X3'], name='X') In [19]: result = pd.concat([df1, s1], axis=1) 
 
../_images/merging_concat_mixed_ndim.png

注意

由於我們將a串聯Series到a DataFrame,因此我們可以用達到相同的結果DataFrame.assign()要串聯任意數量的熊貓對象(DataFrameSeries),請使用 concat

如果未命名Series,則將連續編號。

In [20]: s2 = pd.Series(['_0', '_1', '_2', '_3']) In [21]: result = pd.concat([df1, s2, s2, s2], axis=1) 
 
../_images/merging_concat_unnamed_series.png

通過ignore_index=True將刪除所有名稱引用。

In [22]: result = pd.concat([df1, s1], axis=1, ignore_index=True) 
 
../_images/merging_concat_series_ignore_index.png

與組鍵更多串聯

keys參數的一個相當普遍的用法是在DataFrame基於現有的創建新參數時覆蓋列名稱Series請注意,默認行為是如何使結果(如果存在)DataFrame 繼承父Series名稱的。

In [23]: s3 = pd.Series([0, 1, 2, 3], name='foo') In [24]: s4 = pd.Series([0, 1, 2, 3]) In [25]: s5 = pd.Series([0, 1, 4, 5]) In [26]: pd.concat([s3, s4, s5], axis=1) Out[26]:   foo 0 1 0 0 0 0 1 1 1 1 2 2 2 4 3 3 3 5 

通過keys參數,我們可以覆蓋現有的列名。

In [27]: pd.concat([s3, s4, s5], axis=1, keys=['red', 'blue', 'yellow']) Out[27]:   red blue yellow 0 0 0 0 1 1 1 1 2 2 2 4 3 3 3 5 

讓我們考慮第一個示例的變體:

In [28]: result = pd.concat(frames, keys=['x', 'y', 'z']) 
 
../_images/merging_concat_group_keys2.png

您還可以將dict傳遞給,concat在這種情況下,dict鍵將用作keys參數(除非指定了其他鍵):

In [29]: pieces = {'x': df1, 'y': df2, 'z': df3} In [30]: result = pd.concat(pieces) 
 
../_images/merging_concat_dict.png
In [31]: result = pd.concat(pieces, keys=['z', 'y']) 
 
../_images/merging_concat_dict_keys.png

創建的MultiIndex具有從傳遞的鍵和DataFrame片段的索引構成的級別

In [32]: result.index.levels Out[32]: FrozenList([['z', 'y'], [4, 5, 6, 7, 8, 9, 10, 11]]) 

如果您希望指定其他級別(有時會這樣),則可以使用以下levels參數:

In [33]: result = pd.concat(pieces, keys=['x', 'y', 'z'],  ....: levels=[['z', 'y', 'x', 'w']],  ....: names=['group_key'])  ....: 
 
../_images/merging_concat_dict_keys_names.png
In [34]: result.index.levels Out[34]: FrozenList([['z', 'y', 'x', 'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]) 

這是相當深奧的,但是實際上對於實現GroupBy之類的東西(分類變量的順序有意義)是必要的。

行追加到數據幀

盡管效率不是特別高(因為必須創建一個新對象),但您可以DataFrame通過向傳遞一個Series或dict來將單個行附加到上 append,這將DataFrame如上所述返回一個新值

In [35]: s2 = pd.Series(['X0', 'X1', 'X2', 'X3'], index=['A', 'B', 'C', 'D']) In [36]: result = df1.append(s2, ignore_index=True) 
 
../_images/merging_append_series_as_row.png

您應該使用ignore_index此方法來指示DataFrame放棄其索引。如果希望保留索引,則應構造一個索引適當的DataFrame並附加或連接這些對象。

您還可以傳遞字典或系列的列表:

In [37]: dicts = [{'A': 1, 'B': 2, 'C': 3, 'X': 4},  ....: {'A': 5, 'B': 6, 'C': 7, 'Y': 8}]  ....: In [38]: result = df1.append(dicts, ignore_index=True, sort=False) 
 
../_images/merging_append_dits.png

數據庫樣式的DataFrame或命名的Series加入/合並

pandas具有功能全面的,高性能的內存中連接操作,這在邏輯上與SQL等關系數據庫非常相似。與其他開放源代碼實現(如base::merge.data.frame R中)相比,這些方法的性能明顯更好(在某些情況下要好一個數量級)。這樣做的原因是仔細的算法設計和.NET中數據的內部布局DataFrame

有關某些高級策略,請參見本食譜

熟悉SQL但對熊貓不熟悉的用戶可能會對與SQL比較感興趣 

pandas提供了一個功能,merge()作為DataFrame或命名Series對象之間所有標准數據庫聯接操作的入口點

pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None) 
  • left:一個DataFrame或命名為Series的對象。

  • right:另一個DataFrame或命名為Series的對象。

  • on:要加入的列或索引級別名稱。必須在左右DataFrame和/或Series對象中找到。如果沒有通過,left_index並且 right_indexFalse在DataFrames和/或系列列的交叉點會被推斷為聯接鍵。

  • left_on:左側DataFrame或Series中的列或索引級別用作鍵。可以是列名稱,索引級別名稱,也可以是長度等於DataFrame或Series長度的數組。

  • right_on:右側DataFrame或Series中的列或索引級別用作鍵。可以是列名稱,索引級別名稱,也可以是長度等於DataFrame或Series長度的數組。

  • left_index:如果為True,則使用左側DataFrame或Series中的索引(行標簽)作為其連接鍵。對於具有MultiIndex(分層結構)的DataFrame或Series,級別數必須與正確的DataFrame或Series中的聯接鍵數匹配。

  • right_index:與left_index正確的DataFrame或Series的用法相同

  • how:其一'left''right''outer''inner'默認為inner有關每種方法的詳細說明,請參見下文。

  • sort:按字典順序按連接鍵對結果DataFrame進行排序。默認為True,設置為False可以在許多情況下顯着提高性能。

  • suffixes:適用於重疊列的字符串后綴元組。默認為('_x', '_y')

  • copy注意:始終True從傳遞的DataFrame或命名的Series對象復制數據(默認),即使不需要重新索引也是如此。在很多情況下都無法避免,但是可以提高性能/內存使用率。可以避免復制的情況有些病態,但是仍然提供了此選項。

  • indicator:將一列添加到輸出DataFrame中_merge ,並在每一行的源上提供信息。_merge是分類類型的,left_only對於其合並鍵僅出現在'left'DataFrame或Series中right_only的觀察值,對於僅其合並鍵僅出現在'right'DataFrame或Series中both的觀察值以及兩個視圖中均找到觀察值的合並鍵取值為。

  • validate:字符串,默認為無。如果指定,則檢查合並是否為指定的類型。

    • “ one_to_one”或“ 1:1”:檢查合並鍵在左右數據集中是否唯一。

    • “ one_to_many”或“ 1:m”:檢查合並鍵在左數據集中是否唯一。

    • “ many_to_one”或“ m:1”:檢查合並鍵在正確的數據集中是否唯一。

    • “ many_to_many”或“ m:m”:允許,但不進行檢查。

注意

用於指定索引水平支撐onleft_on以及 right_on在0.23.0版加入參數。Series在版本0.24.0中添加了對合並命名對象的支持

返回類型將與相同left如果leftDataFrame或的名稱,Series 並且right是的子類DataFrame,則返回類型仍為DataFrame

merge是pandas命名空間中的一個函數,它也可以作為 DataFrame實例方法merge()使用,調用 DataFrame被隱式視為聯接中的左側對象。

相關join()方法在merge內部用於索引索引連接(默認情況下)和索引列連接。如果僅在索引上加入,則可能希望使用DataFrame.join來節省一些輸入。

合並方法簡要入門(關系代數)

諸如SQL之類的關系數據庫的經驗豐富的用戶將熟悉用於描述兩個類似於SQL表的結構(DataFrame對象)之間的聯接操作的術語需要考慮的幾種情況非常重要:

  • 一對一聯接:例如,在兩個DataFrame對象的索引上聯接時(必須包含唯一值)。

  • 多對一聯接:例如,將索引(唯一)聯接到different中的一個或多個列時DataFrame

  • 多對多聯接:在列上聯接列。

注意

在列上連接列時(可能是多對多連接),傳遞的DataFrame對象上的任何索引都將被丟棄

值得花一些時間來理解多對多 連接案例的結果。在SQL /標准關系代數中,如果兩個表中的鍵組合都出現多次,則結果表將具有關聯數據笛卡爾積這是一個具有一個唯一鍵組合的非常基本的示例:

In [39]: left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],  ....: 'A': ['A0', 'A1', 'A2', 'A3'],  ....: 'B': ['B0', 'B1', 'B2', 'B3']})  ....: In [40]: right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],  ....: 'C': ['C0', 'C1', 'C2', 'C3'],  ....: 'D': ['D0', 'D1', 'D2', 'D3']})  ....: In [41]: result = pd.merge(left, right, on='key') 
 
../_images/merging_merge_on_key.png

這是帶有多個聯接鍵的更復雜的示例。由於默認情況下只有出現left出現的關鍵right點(相交) how='inner'

In [42]: left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],  ....: 'key2': ['K0', 'K1', 'K0', 'K1'],  ....: 'A': ['A0', 'A1', 'A2', 'A3'],  ....: 'B': ['B0', 'B1', 'B2', 'B3']})  ....: In [43]: right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],  ....: 'key2': ['K0', 'K0', 'K0', 'K0'],  ....: 'C': ['C0', 'C1', 'C2', 'C3'],  ....: 'D': ['D0', 'D1', 'D2', 'D3']})  ....: In [44]: result = pd.merge(left, right, on=['key1', 'key2']) 
 
../_images/merging_merge_on_key_multiple.png

how到參數merge指定如何確定哪些鍵要被包括在所得到的表。如果左表或右表中都沒有按鍵組合,則聯接表中的值將為 NA以下是how選項及其SQL等效名稱的摘要

合並方式

SQL連接名稱

描述

left

LEFT OUTER JOIN

僅使用左框中的關鍵點

right

RIGHT OUTER JOIN

僅從右框使用按鍵

outer

FULL OUTER JOIN

使用兩個框架中的鍵並集

inner

INNER JOIN

使用兩個幀的關鍵點交集

In [45]: result = pd.merge(left, right, how='left', on=['key1', 'key2']) 
 
../_images/merging_merge_on_key_left.png
In [46]: result = pd.merge(left, right, how='right', on=['key1', 'key2']) 
 
../_images/merging_merge_on_key_right.png
In [47]: result = pd.merge(left, right, how='outer', on=['key1', 'key2']) 
 
../_images/merging_merge_on_key_outer.png
In [48]: result = pd.merge(left, right, how='inner', on=['key1', 'key2']) 
 
../_images/merging_merge_on_key_inner.png

如果MultiIndex的名稱與DataFrame中的列相對應,則可以合並多索引的Series和DataFrame。Series.reset_index()合並之前,使用系列將Series轉換為DataFrame ,如以下示例所示。

In [49]: df = pd.DataFrame({"Let": ["A", "B", "C"], "Num": [1, 2, 3]}) In [50]: df Out[50]:   Let Num 0 A 1 1 B 2 2 C 3 In [51]: ser = pd.Series(  ....: ["a", "b", "c", "d", "e", "f"],  ....: index=pd.MultiIndex.from_arrays(  ....: [["A", "B", "C"] * 2, [1, 2, 3, 4, 5, 6]], names=["Let", "Num"]  ....: ),  ....: )  ....: In [52]: ser Out[52]:  Let Num A 1 a B 2 b C 3 c A 4 d B 5 e C 6 f dtype: object In [53]: pd.merge(df, ser.reset_index(), on=['Let', 'Num']) Out[53]:   Let Num 0 0 A 1 a 1 B 2 b 2 C 3 c 

這是另一個在DataFrames中具有重復聯接鍵的示例:

In [54]: left = pd.DataFrame({'A': [1, 2], 'B': [2, 2]}) In [55]: right = pd.DataFrame({'A': [4, 5, 6], 'B': [2, 2, 2]}) In [56]: result = pd.merge(left, right, on='B', how='outer') 
 
../_images/merging_merge_on_key_dup.png

警告

在重復鍵上進行聯接/合並會導致返回的幀是行尺寸的乘積,這可能導致內存溢出。在加入大型DataFrame之前,用戶有責任管理鍵中的重復值。

檢查重復鍵

用戶可以使用該validate參數自動檢查其合並鍵中是否有意外的重復項。在合並操作之前檢查鍵的唯一性,因此應防止內存溢出。檢查密鑰唯一性也是確保用戶數據結構符合預期的好方法。

在以下示例中,Bright中 存在重復的值DataFrame由於這不是validate參數中指定的一對一合並,因此 將引發異常。

In [57]: left = pd.DataFrame({'A' : [1,2], 'B' : [1, 2]}) In [58]: right = pd.DataFrame({'A' : [4,5,6], 'B': [2, 2, 2]}) 
In [53]: result = pd.merge(left, right, on='B', how='outer', validate="one_to_one") ... MergeError: Merge keys are not unique in right dataset; not a one-to-one merge 

如果用戶知道右邊的重復項,DataFrame但要確保左邊的DataFrame中沒有重復項,則可以改用該 validate='one_to_many'參數,這不會引發異常。

In [59]: pd.merge(left, right, on='B', how='outer', validate="one_to_many") Out[59]:   A_x B A_y 0 1 1 NaN 1 2 2 4.0 2 2 2 5.0 3 2 2 6.0 

該合並指標

merge()接受論點indicator如果為True_merge則將將一個名為Categorical-type的列添加到采用值的輸出對象:

觀察原點

_merge 值

僅在'left'框架中合並關鍵點

left_only

僅在'right'框架中合並關鍵點

right_only

在兩個框架中合並關鍵點

both

In [60]: df1 = pd.DataFrame({'col1': [0, 1], 'col_left': ['a', 'b']}) In [61]: df2 = pd.DataFrame({'col1': [1, 2, 2], 'col_right': [2, 2, 2]}) In [62]: pd.merge(df1, df2, on='col1', how='outer', indicator=True) Out[62]:   col1 col_left col_right _merge 0 0 a NaN left_only 1 1 b 2.0 both 2 2 NaN 2.0 right_only 3 2 NaN 2.0 right_only 

indicator參數還將接受字符串參數,在這種情況下,指標函數將使用傳遞的字符串的值作為指標列的名稱。

In [63]: pd.merge(df1, df2, on='col1', how='outer', indicator='indicator_column') Out[63]:   col1 col_left col_right indicator_column 0 0 a NaN left_only 1 1 b 2.0 both 2 2 NaN 2.0 right_only 3 2 NaN 2.0 right_only 

合並dtypes 

合並將保留聯接鍵的dtype。

In [64]: left = pd.DataFrame({'key': [1], 'v1': [10]}) In [65]: left Out[65]:   key v1 0 1 10 In [66]: right = pd.DataFrame({'key': [1, 2], 'v1': [20, 30]}) In [67]: right Out[67]:   key v1 0 1 20 1 2 30 

我們能夠保留聯接鍵:

In [68]: pd.merge(left, right, how='outer') Out[68]:   key v1 0 1 10 1 1 20 2 2 30 In [69]: pd.merge(left, right, how='outer').dtypes Out[69]:  key int64 v1 int64 dtype: object 

當然,如果您缺少引入的值,那么生成的dtype將被轉換。

In [70]: pd.merge(left, right, how='outer', on='key') Out[70]:   key v1_x v1_y 0 1 10.0 20 1 2 NaN 30 In [71]: pd.merge(left, right, how='outer', on='key').dtypes Out[71]:  key int64 v1_x float64 v1_y int64 dtype: object 

合並將保留category人種的dtypes。另請參閱“類別”部分

左框架。

In [72]: from pandas.api.types import CategoricalDtype In [73]: X = pd.Series(np.random.choice(['foo', 'bar'], size=(10,))) In [74]: X = X.astype(CategoricalDtype(categories=['foo', 'bar'])) In [75]: left = pd.DataFrame({'X': X,  ....: 'Y': np.random.choice(['one', 'two', 'three'],  ....: size=(10,))})  ....: In [76]: left Out[76]:   X Y 0 bar one 1 foo one 2 foo three 3 bar three 4 foo one 5 bar one 6 bar three 7 bar three 8 bar three 9 foo three In [77]: left.dtypes Out[77]:  X category Y object dtype: object 

正確的框架。

In [78]: right = pd.DataFrame({'X': pd.Series(['foo', 'bar'],  ....: dtype=CategoricalDtype(['foo', 'bar'])),  ....: 'Z': [1, 2]})  ....: In [79]: right Out[79]:   X Z 0 foo 1 1 bar 2 In [80]: right.dtypes Out[80]:  X category Z int64 dtype: object 

合並結果:

In [81]: result = pd.merge(left, right, how='outer') In [82]: result Out[82]:   X Y Z 0 bar one 2 1 bar three 2 2 bar one 2 3 bar three 2 4 bar three 2 5 bar three 2 6 foo one 1 7 foo three 1 8 foo one 1 9 foo three 1 In [83]: result.dtypes Out[83]:  X category Y object Z int64 dtype: object 

注意

類別dtype必須完全相同,這意味着相同的類別和有序屬性。否則結果將強制為類別的dtype。

注意

categorydtype合並相比,在相同的dtype上合並可能會表現出色object

加入索引

DataFrame.join()是一種將兩個可能具有不同索引的列DataFrames合並為單個結果 的便捷方法DataFrame這是一個非常基本的示例:

In [84]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],  ....: 'B': ['B0', 'B1', 'B2']},  ....: index=['K0', 'K1', 'K2'])  ....: In [85]: right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],  ....: 'D': ['D0', 'D2', 'D3']},  ....: index=['K0', 'K2', 'K3'])  ....: In [86]: result = left.join(right) 
 
../_images/merging_join.png
In [87]: result = left.join(right, how='outer') 
 
../_images/merging_join_outer.png

與上述相同,但帶有how='inner'

In [88]: result = left.join(right, how='inner') 
 
../_images/merging_join_inner.png

此處的數據對齊在索引(行標簽)上。使用merge指示其使用索引的附加參數可以實現相同的行為

In [89]: result = pd.merge(left, right, left_index=True, right_index=True, how='outer') 
 
../_images/merging_merge_index_outer.png
In [90]: result = pd.merge(left, right, left_index=True, right_index=True, how='inner'); 
 
../_images/merging_merge_index_inner.png

在索引上關鍵列

join()接受一個可選on參數,該參數可以是一列或多個列名,它指定傳遞的DataFrame內容將與中的該列對齊DataFrame這兩個函數調用是完全等效的:

left.join(right, on=key_or_keys) pd.merge(left, right, left_on=key_or_keys, right_index=True, how='left', sort=False) 

顯然,您可以選擇任何一種更方便的形式。對於多對一連接(其中的一個DataFrame已通過連接鍵索引),使用join可能會更方便。這是一個簡單的示例:

In [91]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],  ....: 'B': ['B0', 'B1', 'B2', 'B3'],  ....: 'key': ['K0', 'K1', 'K0', 'K1']})  ....: In [92]: right = pd.DataFrame({'C': ['C0', 'C1'],  ....: 'D': ['D0', 'D1']},  ....: index=['K0', 'K1'])  ....: In [93]: result = left.join(right, on='key') 
 
../_images/merging_join_key_columns.png
In [94]: result = pd.merge(left, right, left_on='key', right_index=True,  ....: how='left', sort=False);  ....: 
 
../_images/merging_merge_key_columns.png

要加入多個鍵,傳遞的DataFrame必須具有MultiIndex

In [95]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],  ....: 'B': ['B0', 'B1', 'B2', 'B3'],  ....: 'key1': ['K0', 'K0', 'K1', 'K2'],  ....: 'key2': ['K0', 'K1', 'K0', 'K1']})  ....: In [96]: index = pd.MultiIndex.from_tuples([('K0', 'K0'), ('K1', 'K0'),  ....: ('K2', 'K0'), ('K2', 'K1')])  ....: In [97]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],  ....: 'D': ['D0', 'D1', 'D2', 'D3']},  ....: index=index)  ....: 

現在,可以通過傳遞兩個關鍵列名稱來進行連接:

In [98]: result = left.join(right, on=['key1', 'key2']) 
 
../_images/merging_join_multikeys.png

默認的DataFrame.join是執行左聯接(對於Excel用戶,本質上是“ VLOOKUP”操作),該聯接僅使用在調用DataFrame中找到的鍵。其他聯接類型(例如內部聯接)也可以輕松執行:

In [99]: result = left.join(right, on=['key1', 'key2'], how='inner') 
 
../_images/merging_join_multikeys_inner.png

如您所見,這將刪除所有不匹配的行。

加入單一指數為多指標

您可以將一個索引DataFrame與一個MultiIndexed級別連接DataFrame級別將在單索引幀的索引名稱與MultiIndexed幀的級別名稱上匹配。

In [100]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],  .....: 'B': ['B0', 'B1', 'B2']},  .....: index=pd.Index(['K0', 'K1', 'K2'], name='key'))  .....: In [101]: index = pd.MultiIndex.from_tuples([('K0', 'Y0'), ('K1', 'Y1'),  .....: ('K2', 'Y2'), ('K2', 'Y3')],  .....: names=['key', 'Y'])  .....: In [102]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],  .....: 'D': ['D0', 'D1', 'D2', 'D3']},  .....: index=index)  .....: In [103]: result = left.join(right, how='inner') 
 
../_images/merging_join_multiindex_inner.png

這是等效的,但是比它更冗長,存儲效率更高/更快。

In [104]: result = pd.merge(left.reset_index(), right.reset_index(),  .....: on=['key'], how='inner').set_index(['key','Y'])  .....: 
 
../_images/merging_merge_multiindex_alternative.png

有兩個MultiIndexes加入

只要在連接中完全使用了右參數的索引,並且該參數是左參數中索引的子集,就可以用有限的方式來支持它,如下例所示:

In [105]: leftindex = pd.MultiIndex.from_product([list('abc'), list('xy'), [1, 2]],  .....: names=['abc', 'xy', 'num'])  .....: In [106]: left = pd.DataFrame({'v1': range(12)}, index=leftindex) In [107]: left Out[107]:   v1 abc xy num a x 1 0  2 1  y 1 2  2 3 b x 1 4  2 5  y 1 6  2 7 c x 1 8  2 9  y 1 10  2 11 In [108]: rightindex = pd.MultiIndex.from_product([list('abc'), list('xy')],  .....: names=['abc', 'xy'])  .....: In [109]: right = pd.DataFrame({'v2': [100 * i for i in range(1, 7)]}, index=rightindex) In [110]: right Out[110]:   v2 abc xy a x 100  y 200 b x 300  y 400 c x 500  y 600 In [111]: left.join(right, on=['abc', 'xy'], how='inner') Out[111]:   v1 v2 abc xy num a x 1 0 100  2 1 100  y 1 2 200  2 3 200 b x 1 4 300  2 5 300  y 1 6 400  2 7 400 c x 1 8 500  2 9 500  y 1 10 600  2 11 600 

如果不滿足該條件,則可以使用以下代碼完成具有兩個多索引的聯接。

In [112]: leftindex = pd.MultiIndex.from_tuples([('K0', 'X0'), ('K0', 'X1'),  .....: ('K1', 'X2')],  .....: names=['key', 'X'])  .....: In [113]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],  .....: 'B': ['B0', 'B1', 'B2']},  .....: index=leftindex)  .....: In [114]: rightindex = pd.MultiIndex.from_tuples([('K0', 'Y0'), ('K1', 'Y1'),  .....: ('K2', 'Y2'), ('K2', 'Y3')],  .....: names=['key', 'Y'])  .....: In [115]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],  .....: 'D': ['D0', 'D1', 'D2', 'D3']},  .....: index=rightindex)  .....: In [116]: result = pd.merge(left.reset_index(), right.reset_index(),  .....: on=['key'], how='inner').set_index(['key', 'X', 'Y'])  .....: 
 
../_images/merging_merge_two_multiindex.png

合並列和索引級別的組合

0.23版中的新功能。

字符串作為傳遞onleft_onright_on參數可以指列名或索引級別名稱。這樣就可以DataFrame在索引級別和列的組合上合並 實例,而無需重置索引。

In [117]: left_index = pd.Index(['K0', 'K0', 'K1', 'K2'], name='key1') In [118]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],  .....: 'B': ['B0', 'B1', 'B2', 'B3'],  .....: 'key2': ['K0', 'K1', 'K0', 'K1']},  .....: index=left_index)  .....: In [119]: right_index = pd.Index(['K0', 'K1', 'K2', 'K2'], name='key1') In [120]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],  .....: 'D': ['D0', 'D1', 'D2', 'D3'],  .....: 'key2': ['K0', 'K0', 'K0', 'K1']},  .....: index=right_index)  .....: In [121]: result = left.merge(right, on=['key1', 'key2']) 
 
../_images/merge_on_index_and_column.png

注意

當將DataFrame合並到與兩個框架中的索引級別都匹配的字符串上時,索引級別將保留為結果DataFrame中的索引級別。

注意

當僅使用MultiIndex的某些級別合並DataFrame時,多余的級別將從結果合並中刪除。為了保留這些級別,請reset_index在執行合並之前將這些級別名稱用於將這些級別移動到列。

注意

如果字符串與列名和索引級名稱都匹配,則會發出警告,並且列優先。這將在將來的版本中導致歧義錯誤。

值列重疊

mergesuffixes參數將字符串列表的元組附加到輸入DataFrames中重疊的列名稱上,以消除結果列的歧義:

In [122]: left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]}) In [123]: right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]}) In [124]: result = pd.merge(left, right, on='k') 
 
../_images/merging_merge_overlapped.png
In [125]: result = pd.merge(left, right, on='k', suffixes=('_l', '_r')) 
 
../_images/merging_merge_overlapped_suffix.png

DataFrame.join()具有lsuffixrsuffix行為相似的參數。

In [126]: left = left.set_index('k') In [127]: right = right.set_index('k') In [128]: result = left.join(right, lsuffix='_l', rsuffix='_r') 
 
../_images/merging_merge_overlapped_multi_suffix.png

連接多個DataFrames 

DataFrames也可以傳遞一個列表或元組join() 將它們連接到它們的索引上。

In [129]: right2 = pd.DataFrame({'v': [7, 8, 9]}, index=['K1', 'K1', 'K2']) In [130]: result = left.join([right, right2]) 
 
../_images/merging_join_multi_df.png

將Series或DataFrame列中的值合並在一起

另一個相當常見的情況是有兩個像索引(或類似索引)SeriesDataFrame對象和從值想“補丁”值在一個對象匹配的其他指數。這是一個例子:

In [131]: df1 = pd.DataFrame([[np.nan, 3., 5.], [-4.6, np.nan, np.nan],  .....: [np.nan, 7., np.nan]])  .....: In [132]: df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]],  .....: index=[1, 2])  .....: 

為此,請使用以下combine_first()方法:

In [133]: result = df1.combine_first(df2) 
 
../_images/merging_combine_first.png

請注意,DataFrame如果左側缺少這些值,則此方法僅采用右側的值DataFrame相關方法update()更改了非NA值:

In [134]: df1.update(df2) 
 
../_images/merging_update.png

時間序列友好合並

合並排序的數據

一個merge_ordered()功能允許組合時間序列和其他有序數據。特別是,它具有一個可選fill_method關鍵字來填充/內插丟失的數據:

In [135]: left = pd.DataFrame({'k': ['K0', 'K1', 'K1', 'K2'],  .....: 'lv': [1, 2, 3, 4],  .....: 's': ['a', 'b', 'c', 'd']})  .....: In [136]: right = pd.DataFrame({'k': ['K1', 'K2', 'K4'],  .....: 'rv': [1, 2, 3]})  .....: In [137]: pd.merge_ordered(left, right, fill_method='ffill', left_by='s') Out[137]:   k lv s rv 0 K0 1.0 a NaN 1 K1 1.0 a 1.0 2 K2 1.0 a 2.0 3 K4 1.0 a 3.0 4 K1 2.0 b 1.0 5 K2 2.0 b 2.0 6 K4 2.0 b 3.0 7 K1 3.0 c 1.0 8 K2 3.0 c 2.0 9 K4 3.0 c 3.0 10 K1 NaN d 1.0 11 K2 4.0 d 2.0 12 K4 4.0 d 3.0 

合並ASOF 

Amerge_asof()與有序左聯接相似,不同之處在於我們在最接近的鍵而不是相等的鍵上進行匹配。對於中的每一行left DataFrame,我們選擇right DataFrameon鍵小於左鍵的最后一行兩個DataFrame都必須按鍵排序。

可選地,asof合並可以執行逐組合並。by除了鍵上最接近的匹配之外,此 鍵均等地匹配on鍵。

例如; 我們可能有tradesquotes我們想asof 將它們合並。

In [138]: trades = pd.DataFrame({  .....: 'time': pd.to_datetime(['20160525 13:30:00.023',  .....: '20160525 13:30:00.038',  .....: '20160525 13:30:00.048',  .....: '20160525 13:30:00.048',  .....: '20160525 13:30:00.048']),  .....: 'ticker': ['MSFT', 'MSFT',  .....: 'GOOG', 'GOOG', 'AAPL'],  .....: 'price': [51.95, 51.95,  .....: 720.77, 720.92, 98.00],  .....: 'quantity': [75, 155,  .....: 100, 100, 100]},  .....: columns=['time', 'ticker', 'price', 'quantity'])  .....: In [139]: quotes = pd.DataFrame({  .....: 'time': pd.to_datetime(['20160525 13:30:00.023',  .....: '20160525 13:30:00.023',  .....: '20160525 13:30:00.030',  .....: '20160525 13:30:00.041',  .....: '20160525 13:30:00.048',  .....: '20160525 13:30:00.049',  .....: '20160525 13:30:00.072',  .....: '20160525 13:30:00.075']),  .....: 'ticker': ['GOOG', 'MSFT', 'MSFT',  .....: 'MSFT', 'GOOG', 'AAPL', 'GOOG',  .....: 'MSFT'],  .....: 'bid': [720.50, 51.95, 51.97, 51.99,  .....: 720.50, 97.99, 720.50, 52.01],  .....: 'ask': [720.93, 51.96, 51.98, 52.00,  .....: 720.93, 98.01, 720.88, 52.03]},  .....: columns=['time', 'ticker', 'bid', 'ask'])  .....: 
In [140]: trades Out[140]:   time ticker price quantity 0 2016-05-25 13:30:00.023 MSFT 51.95 75 1 2016-05-25 13:30:00.038 MSFT 51.95 155 2 2016-05-25 13:30:00.048 GOOG 720.77 100 3 2016-05-25 13:30:00.048 GOOG 720.92 100 4 2016-05-25 13:30:00.048 AAPL 98.00 100 In [141]: quotes Out[141]:   time ticker bid ask 0 2016-05-25 13:30:00.023 GOOG 720.50 720.93 1 2016-05-25 13:30:00.023 MSFT 51.95 51.96 2 2016-05-25 13:30:00.030 MSFT 51.97 51.98 3 2016-05-25 13:30:00.041 MSFT 51.99 52.00 4 2016-05-25 13:30:00.048 GOOG 720.50 720.93 5 2016-05-25 13:30:00.049 AAPL 97.99 98.01 6 2016-05-25 13:30:00.072 GOOG 720.50 720.88 7 2016-05-25 13:30:00.075 MSFT 52.01 52.03 

默認情況下,我們采用引號的形式。

In [142]: pd.merge_asof(trades, quotes,  .....: on='time',  .....: by='ticker')  .....: Out[142]:   time ticker price quantity bid ask 0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96 1 2016-05-25 13:30:00.038 MSFT 51.95 155 51.97 51.98 2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93 3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93 4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN 

我們只在2ms報價時間和交易時間之間進行交易。

In [143]: pd.merge_asof(trades, quotes,  .....: on='time',  .....: by='ticker',  .....: tolerance=pd.Timedelta('2ms'))  .....: Out[143]:   time ticker price quantity bid ask 0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96 1 2016-05-25 13:30:00.038 MSFT 51.95 155 NaN NaN 2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93 3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93 4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN 

我們僅在10ms報價時間和交易時間之間進行結算,並且不包括准時匹配。請注意,盡管我們排除了(引號)的完全匹配項,但先前的引號確實會傳播到該時間點。

In [144]: pd.merge_asof(trades, quotes,  .....: on='time',  .....: by='ticker',  .....: tolerance=pd.Timedelta('10ms'),  .....: allow_exact_matches=False)  .....: Out[144]:   time ticker price quantity bid ask 0 2016-05-25 13:30:00.023 MSFT 51.95 75 NaN NaN 1 2016-05-25 13:30:00.038 MSFT 51.95 155 51.97 51.98 2 2016-05-25 13:30:00.048 GOOG 720.77 100 NaN NaN 3 2016-05-25 13:30:00.048 GOOG 720.92 100 NaN NaN 4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN 

比較對象

使用compare()compare()方法,您可以分別比較兩個DataFrame或Series,並總結它們之間的差異。

V1.1.0中添加了此功能

例如,您可能想要比較兩個DataFrame並並排堆疊它們的差異。

In [145]: df = pd.DataFrame(  .....: {  .....: "col1": ["a", "a", "b", "b", "a"],  .....: "col2": [1.0, 2.0, 3.0, np.nan, 5.0],  .....: "col3": [1.0, 2.0, 3.0, 4.0, 5.0]  .....: },  .....: columns=["col1", "col2", "col3"],  .....: )  .....: In [146]: df Out[146]:   col1 col2 col3 0 a 1.0 1.0 1 a 2.0 2.0 2 b 3.0 3.0 3 b NaN 4.0 4 a 5.0 5.0 
In [147]: df2 = df.copy() In [148]: df2.loc[0, 'col1'] = 'c' In [149]: df2.loc[2, 'col3'] = 4.0 In [150]: df2 Out[150]:   col1 col2 col3 0 c 1.0 1.0 1 a 2.0 2.0 2 b 3.0 4.0 3 b NaN 4.0 4 a 5.0 5.0 
In [151]: df.compare(df2) Out[151]:   col1 col3  self other self other 0 a c NaN NaN 2 NaN NaN 3.0 4.0 

默認情況下,如果兩個對應的值相等,它們將顯示為NaN此外,如果整個行/列中的所有值都將從結果中省略。其余差異將在列上對齊。

如果需要,可以選擇將差異堆疊在行上。

In [152]: df.compare(df2, align_axis=0) Out[152]:   col1 col3 0 self a NaN  other c NaN 2 self NaN 3.0  other NaN 4.0 

如果您希望保留所有原始行和列,請將keep_shape參數設置True

In [153]: df.compare(df2, keep_shape=True) Out[153]:   col1 col2 col3  self other self other self other 0 a c NaN NaN NaN NaN 1 NaN NaN NaN NaN NaN NaN 2 NaN NaN NaN NaN 3.0 4.0 3 NaN NaN NaN NaN NaN NaN 4 NaN NaN NaN NaN NaN NaN 

您也可以保留所有原始值,即使它們相等。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM