在連接/合並類型操作的情況下,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)

與其在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'])

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

警告
在版本0.23.0中更改。
默認行為join='outer'
是對其他軸排序(在這種情況下為列)。在未來版本的熊貓中,默認設置為不排序。我們指定sort=False
現在選擇加入新行為。
這是同一件事join='inner'
:
In [10]: result = pd.concat([df1, df4], axis=1, join='inner')

最后,假設我們只是想重用原始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

使用串聯append
一個有用的快捷方式concat()
是append()
在實例方法Series
和DataFrame
。這些方法實際上早於 concat
。它們串聯在一起axis=0
,即索引:
In [13]: result = df1.append(df2)

對於DataFrame
,索引必須是不相交的,但列不必是:
In [14]: result = df1.append(df4, sort=False)

append
可能需要多個對象來串聯:
In [15]: result = df1.append([df2, df3])

注意
與append()
追加到原始列表並返回的方法不同None
,append()
這里的方法不會修改 df1
並返回帶有df2
追加內容的副本。
忽略串聯軸上的索引
對於DataFrame
沒有有意義索引的對象,您可能希望追加它們,而忽略它們可能具有重疊索引的事實。為此,請使用ignore_index
參數:
In [16]: result = pd.concat([df1, df4], ignore_index=True, sort=False)

這也是有效的參數DataFrame.append()
:
In [17]: result = df1.append(df4, ignore_index=True, sort=False)

與混合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)

注意
由於我們將a串聯Series
到a DataFrame
,因此我們可以用達到相同的結果DataFrame.assign()
。要串聯任意數量的熊貓對象(DataFrame
或Series
),請使用 concat
。
如果未命名Series
,則將連續編號。
In [20]: s2 = pd.Series(['_0', '_1', '_2', '_3']) In [21]: result = pd.concat([df1, s2, s2, s2], axis=1)

通過ignore_index=True
將刪除所有名稱引用。
In [22]: result = pd.concat([df1, s1], axis=1, ignore_index=True)

與組鍵更多串聯
該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'])

您還可以將dict傳遞給,concat
在這種情況下,dict鍵將用作keys
參數(除非指定了其他鍵):
In [29]: pieces = {'x': df1, 'y': df2, 'z': df3} In [30]: result = pd.concat(pieces)

In [31]: result = pd.concat(pieces, keys=['z', 'y'])

創建的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']) ....:

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)

您應該使用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)

數據庫樣式的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_index
是False
在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”:允許,但不進行檢查。
-
注意
用於指定索引水平支撐on
,left_on
以及 right_on
在0.23.0版加入參數。Series
在版本0.24.0中添加了對合並命名對象的支持。
返回類型將與相同left
。如果left
是DataFrame
或的名稱,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')

這是帶有多個聯接鍵的更復雜的示例。由於默認情況下,只有出現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'])

的how
到參數merge
指定如何確定哪些鍵要被包括在所得到的表。如果左表或右表中都沒有按鍵組合,則聯接表中的值將為 NA
。以下是how
選項及其SQL等效名稱的摘要:
合並方式 |
SQL連接名稱 |
描述 |
---|---|---|
|
|
僅使用左框中的關鍵點 |
|
|
僅從右框使用按鍵 |
|
|
使用兩個框架中的鍵並集 |
|
|
使用兩個幀的關鍵點交集 |
In [45]: result = pd.merge(left, right, how='left', on=['key1', 'key2'])

In [46]: result = pd.merge(left, right, how='right', on=['key1', 'key2'])

In [47]: result = pd.merge(left, right, how='outer', on=['key1', 'key2'])

In [48]: result = pd.merge(left, right, how='inner', on=['key1', 'key2'])

如果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')

警告
在重復鍵上進行聯接/合並會導致返回的幀是行尺寸的乘積,這可能導致內存溢出。在加入大型DataFrame之前,用戶有責任管理鍵中的重復值。
檢查重復鍵
用戶可以使用該validate
參數自動檢查其合並鍵中是否有意外的重復項。在合並操作之前檢查鍵的唯一性,因此應防止內存溢出。檢查密鑰唯一性也是確保用戶數據結構符合預期的好方法。
在以下示例中,B
right中 存在重復的值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。
注意
與category
dtype合並相比,在相同的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)

In [87]: result = left.join(right, how='outer')

與上述相同,但帶有how='inner'
。
In [88]: result = left.join(right, how='inner')

此處的數據對齊在索引(行標簽)上。使用merge
指示其使用索引的附加參數可以實現相同的行為:
In [89]: result = pd.merge(left, right, left_index=True, right_index=True, how='outer')

In [90]: result = pd.merge(left, right, left_index=True, right_index=True, how='inner');

在索引上關鍵列
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')

In [94]: result = pd.merge(left, right, left_on='key', right_index=True, ....: how='left', sort=False); ....:

要加入多個鍵,傳遞的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'])

默認的DataFrame.join
是執行左聯接(對於Excel用戶,本質上是“ VLOOKUP”操作),該聯接僅使用在調用DataFrame中找到的鍵。其他聯接類型(例如內部聯接)也可以輕松執行:
In [99]: result = left.join(right, on=['key1', 'key2'], how='inner')

如您所見,這將刪除所有不匹配的行。
加入單一指數為多指標
您可以將一個索引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')

這是等效的,但是比它更冗長,存儲效率更高/更快。
In [104]: result = pd.merge(left.reset_index(), right.reset_index(), .....: on=['key'], how='inner').set_index(['key','Y']) .....:

有兩個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']) .....:

合並列和索引級別的組合
0.23版中的新功能。
字符串作為傳遞on
,left_on
和right_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'])

注意
當將DataFrame合並到與兩個框架中的索引級別都匹配的字符串上時,索引級別將保留為結果DataFrame中的索引級別。
注意
當僅使用MultiIndex的某些級別合並DataFrame時,多余的級別將從結果合並中刪除。為了保留這些級別,請reset_index
在執行合並之前將這些級別名稱用於將這些級別移動到列。
注意
如果字符串與列名和索引級名稱都匹配,則會發出警告,並且列優先。這將在將來的版本中導致歧義錯誤。
值列重疊
mergesuffixes
參數將字符串列表的元組附加到輸入DataFrame
s中重疊的列名稱上,以消除結果列的歧義:
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')

In [125]: result = pd.merge(left, right, on='k', suffixes=('_l', '_r'))

DataFrame.join()
具有lsuffix
和rsuffix
行為相似的參數。
In [126]: left = left.set_index('k') In [127]: right = right.set_index('k') In [128]: result = left.join(right, lsuffix='_l', rsuffix='_r')

連接多個DataFrames
DataFrames
也可以傳遞一個列表或元組以join()
將它們連接到它們的索引上。
In [129]: right2 = pd.DataFrame({'v': [7, 8, 9]}, index=['K1', 'K1', 'K2']) In [130]: result = left.join([right, right2])

將Series或DataFrame列中的值合並在一起
另一個相當常見的情況是有兩個像索引(或類似索引)Series
或DataFrame
對象和從值想“補丁”值在一個對象匹配的其他指數。這是一個例子:
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)

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

時間序列友好合並
合並排序的數據
一個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
DataFrame
其on
鍵小於左鍵的最后一行。兩個DataFrame都必須按鍵排序。
可選地,asof合並可以執行逐組合並。by
除了鍵上最接近的匹配之外,此 鍵均等地匹配on
鍵。
例如; 我們可能有trades
,quotes
我們想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
您也可以保留所有原始值,即使它們相等。