pandas學習筆記(六)
pandas學習筆記(六) —連線
關係型連線
1.連線的基本概念
連線的兩個重要要素:
鍵:用on引數,將兩張相關的表按照某一個或某一組鍵連線起來是一種操作。
連線的形式:在pandas中的關係型連線函式merge和join中提供了how引數來代表連線的形式,分為:
- 左連線
left
- 右連線
right
- 內連線
inner
- 外連線
outer
它們的區別可以用如下示意圖表示:
如果出現重複的鍵應該如何處理?只需把握一個原則,即只要兩邊同時出現的值,就以笛卡爾積的方式加入;如果單邊出現則根據連線形式進行處理。
笛卡爾積的說明:設左表中鍵 張三
出現兩次,右表中的 張三
也出現兩次,那麼逐個進行匹配,最後產生的表必然包含 2*2
張三
的行。下面是一個對應例子的示意圖:
2.值連結
基於值的連線可以用merge函式實現,列如第一張圖的左連線:
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]}) df1 Out[5]: Name Age 0 San Zhang 20 1 Si Li 30 df2 = pd.DataFrame({'Name':['Si Li','Wu Wang'],'Gender':['F','M']}) df2 Out[7]: Name Gender 0 Si Li F 1 Wu Wang M df1.merge(df2,on='Name',how='left') Out[8]: Name Age Gender 0 San Zhang 20 NaN 1 Si Li 30 F
如果兩個表中想要連線的列不具備相同的列名,可以通過 left_on 和 right_on 指定:
df1 = pd.DataFrame({'df1_name':['San Zhang','Si Li'], ...: 'Age':[20,30]}) df2 = pd.DataFrame({'df2_name':['Si Li','Wu Wang'], ...: 'Gender':['F','M']}) df1.merge(df2,left_on='df1_name',right_on='df2_name',how='left') Out[11]: df1_name Age df2_name Gender 0 San Zhang 20 NaN NaN 1 Si Li 30 Si Li F
如果兩個表中的列出現了重複的列名,那麼可以通過 suffixes 引數指定。例如合併考試成績的時候,第一個表記錄了語文成績,第二個是數學成績:
df1 = pd.DataFrame({'Name':['San Zhang'],'Grade':[70]})
df2 = pd.DataFrame({'Name':['San Zhang'],'Grade':[80]})
df1.merge(df2,on='Name',how='left',suffixes=['_Chinese','_Math'])
Out[19]:
Name Grade_Chinese Grade_Math
0 San Zhang 70 80
在某些時候出現重複元素是麻煩的,例如兩位同學來自不同的班級,但是姓名相同,這種時候就要指定 on 引數為多個列使得正確連線:
df1 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
...: 'Age':[20, 21],
...: 'Class':['one', 'two']})
df2 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
...: 'Gender':['F', 'M'],
...: 'Class':['two', 'one']})
df1
Out[22]:
Name Age Class
0 San Zhang 20 one
1 San Zhang 21 two
df2
Out[23]:
Name Gender Class
0 San Zhang F two
1 San Zhang M one
df1.merge(df2, on='Name', how='left')# 錯誤的操作
Out[24]:
Name Age Class_x Gender Class_y
0 San Zhang 20 one F two
1 San Zhang 20 one M one
2 San Zhang 21 two F two
3 San Zhang 21 two M one
df1.merge(df2, on=['Name', 'Class'], how='left')# 正確的操作
Out[25]:
Name Age Class Gender
0 San Zhang 20 one M
1 San Zhang 21 two F
要保證唯一性,除了用 duplicated
檢查是否重複外, merge
中也提供了 validate
引數來檢查連線的唯一性模式。這裡共有三種模式:
- 一對一連線
1:1 :
指左右表的鍵都是唯一的 - 一對多連線
1:m :
指左表鍵唯一 - 多對一連線
m:1
:指右表鍵唯一
3.索引連線
索引連線:把索引當作鍵,這和值連線本質上沒有區別。
pandas
中利用 join
函式來處理索引連線,它的引數選擇要少於 merge
,除了必須的 on
和 how
之外,可以對重複的列指定左右後綴 lsuffix
和 rsuffix
。其中, on
引數指索引名,單層索引時省略引數表示按照當前索引連線。
df1 = pd.DataFrame({'Age':[20,30]},index=pd.Series(['San Zhang','Si Li'],name='Name'))
df2 = pd.DataFrame({'Gender':['F','M']},
...: index=pd.Series(
...: ['Si Li','Wu Wang'],name='Name'))
df1.join(df2,how='left')
Out[28]:
Age Gender
Name
San Zhang 20 NaN
Si Li 30 F
使用 join
讓語文和數學分數合併:
df1 = pd.DataFrame({'Grade':[70]},
...: index=pd.Series(['San Zhang'],
...: name='Name'))
df2 = pd.DataFrame({'Grade':[80]},
...: index=pd.Series(['San Zhang'],
...: name='Name'))
df1.join(df2, how='left', lsuffix='_Chinese', rsuffix='_Math')
Out[33]:
Grade_Chinese Grade_Math
Name
San Zhang 70 80
join
使用多級索引,類似於 merge
中以多列為鍵的操作:
df1 = pd.DataFrame({'Age':[20,21]},
...: index=pd.MultiIndex.from_arrays(
...: [['San Zhang', 'San Zhang'],['one', 'two']],
...: names=('Name','Class')))
...:
df2 = pd.DataFrame({'Gender':['F', 'M']},
...: index=pd.MultiIndex.from_arrays(
...: [['San Zhang', 'San Zhang'],['two', 'one']],
...: names=('Name','Class')))
...:
df1
Out[38]:
Age
Name Class
San Zhang one 20
two 21
df2
Out[39]:
Gender
Name Class
San Zhang two F
one M
df1.join(df2)
Out[40]:
Age Gender
Name Class
San Zhang one 20 M
two 21 F
方向連線
1.concat
關係型連線,以某一列或者多列為鍵來合併,其中最重要的引數是 on
和 how
。但有時候把兩個表或者多個表按照縱向或橫向拼接,pandas
中提供了 concat
函式來實現。
在 concat
中,最常用的有三個引數:
axis :
表示拼接方向,在預設狀態下的axis=0
,表示縱向拼接多個表,常用於多個樣本的拼接;而axis=1
表示橫向拼接多個表,常用於多個欄位或特徵的拼接join :表示
連線形式keys
: 表示在新表中指示來自於哪一張舊錶的名字
注意: 這裡的join
和 keys
與上面的 join
函式和鍵的概念沒有任何關係。
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],
...: 'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Wu Wang'], 'Age':[40]})
pd.concat([df1,df2])
Out[43]:
Name Age
0 San Zhang 20
1 Si Li 30
0 Wu Wang 40
df2 = pd.DataFrame({'Grade':[80, 90]})
df3 = pd.DataFrame({'Gender':['M', 'F']})
pd.concat({'Gender':['M',F]})
pd.concat([df1,df2,df3],1)
Out[49]:
Name Age Grade Gender
0 San Zhang 20 80 M
1 Si Li 30 90 F
concat
是關於索引進行連線的。縱向拼接會根據列索引對其,預設狀態下 join=outer ,表示保留所有的列,並將不存在的值設為缺失; join=inner ,表示保留兩個表都出現過的列。橫向拼接則根據行索引對齊, join
引數可以類似設定。
df2 = pd.DataFrame({'Name':['Wu Wang'], 'Gender':['M']})
df2
Out[53]:
Name Gender
0 Wu Wang M
pd.concat([df1, df2])
Out[54]:
Name Age Gender
0 San Zhang 20.0 NaN
1 Si Li 30.0 NaN
0 Wu Wang NaN M
df2 = pd.DataFrame({'Grade':[80, 90]}, index=[1, 2])
...: pd.concat([df1, df2], 1)
...:
Out[56]:
Name Age Grade
0 San Zhang 20.0 NaN
1 Si Li 30.0 80.0
2 NaN NaN 90.0
pd.concat([df1, df2], axis=1, join='inner')
Out[57]:
Name Age Grade
1 Si Li 30 80
注意:
確認要使用多表直接的方向合併時,尤其是橫向的合併,可以先用
reset_index
方法恢復預設整數索引再進行合併,防止出現由索引的誤對齊和重複索引的笛卡爾積帶來的錯誤結果。
keys
引數的使用場景在於多個表合併後,使用者仍然想要知道新表中的資料來自於哪個原表,這時可以通過 keys
引數產生多級索引進行標記。
df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],
...: 'Age':[20,21]})
df2 = pd.DataFrame({'Name':['Wu Wang'],'Age':[21]})
pd.concat([df1, df2], keys=['one', 'two'])
Out[60]:
Name Age
one 0 San Zhang 20
1 Si Li 21
two 0 Wu Wang 21
2.序列與表的合併
把一個序列追加到表的行末或者列末,則可以分別使用 append
和 assign
方法。在 append
中,如果原表是預設整數序列的索引,那麼可以使用 ignore_index=True
對新序列對應索引的自動標號,否則必須對 Series
指定 name
屬性。
s = pd.Series(['Wu Wang', 21], index = df1.columns)
df1.append(s, ignore_index=True)
Out[62]:
Name Age
0 San Zhang 20
1 Si Li 21
2 Wu Wang 21
assign
通過 df['new_col'] = ...
的形式可以等價地新增新列。同時,使用 []
修改的缺點是它會直接在原表上進行改動,而 assign
返回的是一個臨時副本:
s = pd.Series([80, 90])
df1.assign(Grade=s)
Out[64]:
Name Age Grade
0 San Zhang 20 80
1 Si Li 21 90
df1['Grade'] = s
df1
Out[66]:
Name Age Grade
0 San Zhang 20 80
1 Si Li 21 90
類連線操作
一些函式能夠對兩個表進行某些操作,把它們統稱為類連線操作。
1.比較
compare能夠比較兩個表或者序列的不同處並將其彙總展示:
df1 = pd.DataFrame({'Name':['San Zhang', 'Si Li', 'Wu Wang'],
...: 'Age':[20, 21 ,21],
...: 'Class':['one', 'two', 'three']})
df2 = pd.DataFrame({'Name':['San Zhang', 'Li Si', 'Wu Wang'],
...: 'Age':[20, 21 ,21],
...: 'Class':['one', 'two', 'Three']})
...:
df1.compare(df2)
Out[69]:
Name Class
self other self other
1 Si Li Li Si NaN NaN
2 NaN NaN three Three
結果中返回了不同值所在的行列,如果相同則會被填充為缺失值 NaN
,其中 :
other
:指代傳入的引數表self
:指代被呼叫的表自身
設定 keep_shape=True ,可以完整顯示錶中所有元素的比較情況:
df1.compare(df2,keep_shape=True)
Out[73]:
Name Age Class
self other self other self other
0 NaN NaN NaN NaN NaN NaN
1 Si Li Li Si NaN NaN NaN NaN
2 NaN NaN NaN NaN three Three
2.組合
combine
函式能夠讓兩張表按照一定的規則進行組合,在進行規則比較時會自動進行列索引的對齊。
對於傳入的函式而言,每一次操作中輸入的引數是來自兩個表的同名 Series
,依次傳入的列是兩個表列名的並集。
設定 overtwrite
引數為 False
可以保留 被呼叫表 中未出現在傳入的引數表中的列,而不會設定未缺失值。
注意:
除了
combine
之外,pandas
中還有一個combine_first
方法,其功能是在對兩張表組合時,若第二張表中的值在第一張表中對應索引位置的值不是缺失狀態,那麼就使用第一張表的值填充。