3.8 合併數據集:合併與連接
Pandas的基本特性之一就是高性能的內存式數據鏈接(join)和合並(merge)操作。
3.8.1 數據鏈接的類型
pd.merge()函數實現了三種數據鏈接的類型:一對一、多對一和多對多。這三種數據連接類型都通過pd.merge()接口進行調用。
1.一對一連接
In [1] :import pandas as pd
In [2] :df1 = pd.DataFrame({'employee': ['Bob', 'Jake', 'Lisa', 'Sue'],'group': ['Accounting', 'Engineering', 'Engineering', 'HR']})
df2 = pd.DataFrame({'employee': ['Lisa', 'Bob', 'Jake', 'Sue'],'hire_date': [2004, 2008, 2012, 2014]})
In [3] :df1
Out[3] :
employee group
0 Bob Accounting
1 Jake Engineering
2 Lisa Engineering
3 Sue HR
In [4] :df2
Out[4] :
employee hire_date
0 Lisa 2004
1 Bob 2008
2 Jake 2012
3 Sue 2014
可以看到,兩個df有共同列‘employee ’,若想將這兩個DataFrame合併成一個DataFrame,可以使用pd.merge(),並且會自動以相同列作爲key進行連接:
In [5] :df3 = pd.merge(df1,df2)
df3
Out[5] :
employee group hire_date
0 Bob Accounting 2008
1 Jake Engineering 2012
2 Lisa Engineering 2004
3 Sue HR 2014
兩個df的合併會生成一個新的DataFrame。而且,pd.merge()會默認丟棄原來的行索引,重新生成一個整數行索引。
1.多對一連接
多對一連接是指,在需要連接的兩個列中,有一列的值有重複。通過多對一連接獲得的結果DataFrame將會保留重複值。
In [6] :df4 = pd.DataFrame({'group': ['Accounting', 'Engineering', 'HR'],'supervisor': ['Carly', 'Guido', 'Steve']})
df4
Out[6] :
group supervisor
0 Accounting Carly
1 Engineering Guido
2 HR Steve
In [7] :pd.merge(df3,df4)
Out[7] :
employee group hire_date supervisor
0 Bob Accounting 2008 Carly
1 Jake Engineering 2012 Guido
2 Lisa Engineering 2004 Guido
3 Sue HR 2014 Steve
對於df4中的group列,因爲df3中group列擁有兩個‘Engineering’,所以會自動生成與其對應的連接值。
3.多對多連接
可以理解爲,如果左右兩個輸入的共同列都包含重複值,那麼合併的結果就是一種多對多連接。
In [8] :df5 = pd.DataFrame({'group': ['Accounting', 'Accounting','Engineering', 'Engineering', 'HR', 'HR'],'skills': ['math', 'spreadsheets', 'coding', 'linux',
'spreadsheets', 'organization']})
df5
Out[8] :
group skills
0 Accounting math
1 Accounting spreadsheets
2 Engineering coding
3 Engineering linux
4 HR spreadsheets
5 HR organization
In [9] :pd.merge(df1,df5)
Out[9] :
employee group skills
0 Bob Accounting math
1 Bob Accounting spreadsheets
2 Jake Engineering coding
3 Jake Engineering linux
4 Lisa Engineering coding
5 Lisa Engineering linux
6 Sue HR spreadsheets
7 Sue HR organization
這三種數據連接類型可以直接與其他Pandas 工具組合使用,從而實現各種各樣的功
能。
3.8.2 設置數據合併的鍵
上面所介紹的合併都是擁有共同列名的兩個DataFrame之間的合併,可在工作中更常見的是意義相同,列名卻不同的兩個DataFrame進行合併。pd.merge()提供了一些參數處理這個問題。
1. 參數on的用法
最簡單的方法就是直接將參數on 設置爲一個列名字符串或者一個包含多列名稱的列表:
對於擁有相同列的df使用
In [10] :pd.merge(df1, df2, on='employee')
Out[10] :
employee group hire_date
0 Bob Accounting 2008
1 Jake Engineering 2012
2 Lisa Engineering 2004
3 Sue HR 2014
2. left_on與right_on參數
有時你也需要合併兩個列名不同的數據集,例如前面的員工信息表中有一個字段不是
“employee”而是“name”。在這種情況下,就可以用left_on 和right_on 參數來指定
列名:
In [11] :df3 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],'salary': [70000, 80000, 120000, 90000]})
In [12] :pd.merge(df1, df3, left_on="employee", right_on="name")
Out[12] :
employee group name salary
0 Bob Accounting Bob 70000
1 Jake Engineering Jake 80000
2 Lisa Engineering Lisa 120000
3 Sue HR Sue 90000
3. left_index與right_index參數
除了合併列之外,你可能還需要合併索引。就像下面例子中的數據那樣:
In [13] :df1a = df1.set_index('employee')
df2a = df2.set_index('employee')
In [14] :df1a
group
employee
Bob Accounting
Jake Engineering
Lisa Engineering
Sue HR
In [14] :df2a
hire_date
employee
Lisa 2004
Bob 2008
Jake 2012
Sue 2014
In [15] :pd.merge(df1a,df2a,left_index=True,right_index=True) # 參數必須同時爲True,否則報錯
Out[15] :
group hire_date
employee
Bob Accounting 2008
Jake Engineering 2012
Lisa Engineering 2004
Sue HR 2014
3.8.3 設置數據連接的集合操作規則
pd.merge()合併兩個DataFrame時,默認求交集,這種連接方式被稱爲內連接。
In [15] :df6 = pd.DataFrame({'name': ['Peter', 'Paul', 'Mary'],'food': ['fish', 'beans', 'bread']},columns=['name', 'food'])
In [16] :df7 = pd.DataFrame({'name': ['Mary', 'Joseph'],'drink': ['wine', 'beer']},columns=['name', 'drink'])
In [17] :df6
Out[17] :
name food
0 Peter fish
1 Paul beans
2 Mary bread
In [18] :df7
Out[18] :
name drink
0 Mary wine
1 Joseph beer
In [19] :pd.merge(df6,df7)
Out[19] :
name food drink
0 Mary bread wine
我們可以用how參數設置連接方式,默認爲‘innner’
In [20] :pd.merge(df6, df7, how='inner')
Out[20] :
name food drink
0 Mary bread wine
外連接outer,也就是求並集,缺失值用NaN填充:
In [21] :pd.merge(df6,df7,how="outer")
Out[21] :
name food drink
0 Peter fish NaN
1 Paul beans NaN
2 Mary bread wine
3 Joseph NaN beer
左連接left,只包含相同列左邊的值:
In [22] :pd.merge(df6,df7,how="outer")
Out[22] :
name food drink
0 Peter fish NaN
1 Paul beans NaN
2 Mary bread wine
3 Joseph NaN beer
右連接right,只包含相同列右邊的值:
In [23] :pd.merge(df6,df7,how="right")
Out[23] :
name food drink
0 Mary bread wine
1 Joseph NaN beer
3.8.4 重複列名:suffixes參數
最後,你可能會遇到兩個輸入DataFrame 有重名列的情況。來看看下面的例子:
In [24] :df8 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],'rank': [1, 2, 3, 4]})
df9 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],'rank': [3, 1, 4, 2]})
In [25] :df8
Out[23] :
name rank
0 Bob 1
1 Jake 2
2 Lisa 3
3 Sue 4
In [25] :df9
Out[23] :
name rank
0 Bob 3
1 Jake 1
2 Lisa 4
3 Sue 2
# 對於這種所有列名都相同的DF,必須制定合併key,除非完全相同,否則沒有結果
In [26] :pd.merge(df8,df9)
Out[26] :
name rank
In [27] :pd.merge(df8,df9,on="name")
Out[27] :
name rank_x rank_y
0 Bob 1 3
1 Jake 2 1
2 Lisa 3 4
3 Sue 4 2
由於輸出結果中有兩個重複的列名,因此pd.merge() 函數會自動爲它們增加後綴_x 或_y,當然也可以通過suffixes 參數自定義後綴名:
In [28] :pd.merge(df8,df9,on="name",suffixes=["_L","_R"])
Out[28] :
name rank_L rank_R
0 Bob 1 3
1 Jake 2 1
2 Lisa 3 4
3 Sue 4 2