一、關系型連接
連接:
- 左連接,右連接=>兩者效果相同,只是列位置不一樣
- inner(&)outer(||,全連接)
如果出現(xiàn)兩次,則結果為笛卡爾集,即有4個記錄
| 類型 | 函數(shù) | 參數(shù) | 例子 | 備注 |
|---|---|---|---|---|
| 值連接 | merge | on: 連接的鍵;how:連接方式 | df1.merge(df2, on='Name', how='left') | 出現(xiàn)重復元素時,需要on的參數(shù)值為多個,使其結果唯一 |
| left_on 和 right_on :指定要連接的列 | df1.merge(df2, left_on='df1_name', right_on='df2_name', how='left') | 想要連接的列不具備相同的列名 | ||
| suffixes:指定前綴 | df1.merge(df2, on='Name', how='left', suffixes=['_Chinese','_Math']) | 兩個表中的列出現(xiàn)了重復的列名 | ||
| validate:檢查連接的唯一性模式 | df1.merge(df2, on=['Class','Name'], how='left',validate='1:m') | 共有三種模式,即一對一連接 1:1 ,一對多連接 1:m ,多對一連接 m:1 連接,第一個是指左右表的鍵都是唯一的,后面兩個分別指左表鍵唯一和右表鍵唯一 |
||
| 索引連接 | join | on: 連接的鍵;how:連接方式 | df1.join(df2, how='left') | |
| lsuffix;rsuffix | df1.join(df2, how='left', lsuffix='_Chinese', rsuffix='_Math') |
練一練
上面以多列為鍵的例子中,錯誤寫法顯然是一種多對多連接,而正確寫法是一對一連接,請修改原表,使得以多列為鍵的正確寫法能夠通過
validate='1:m'的檢驗,但不能通過validate='m:1'的檢驗。
df1 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
'Age':[20, 21],
'Class':['one', 'two']})
df2 = pd.DataFrame({'Name':['San Zhang', 'San Zhang'],
'Subject':['Chinese', 'Math'],
'Class':['one', 'two']})
df1.merge(df2, on=['Class','Name'], how='left',validate='1:m')
'''
Name Age Class Subject
0 San Zhang 20 one Chinese
1 San Zhang 20 one Math
2 San Zhang 21 two NaN
'''
二、方向連接
| 分類 | 函數(shù) | 參數(shù) | 例子 | 備注 |
|---|---|---|---|---|
| 合并兩個表 | concat | axis:拼接方向,axis=0 ,表示縱向拼接多個表,常常用于多個樣本的拼接;而 axis=1 表示橫向拼接多個表,常用于多個字段或特征的拼接; |
pd.concat([df1, df2]) | |
| join:連接形式(inner,outer) | pd.concat([df1, df2], axis=1, join='inner') | 橫向連接 | ||
| keys:在新表中指示來自于哪一張舊表的名字 | pd.concat([df1, df2], keys=['one', 'two']) | 可以通過 keys 參數(shù)產(chǎn)生多級索引進行標記 |
||
| 合并序列和表 | append | ignore_index=True對新序列對應索引的自動標號 | df1.append(s, ignore_index=True) | 在 append 中,如果原表是默認整數(shù)序列的索引,那么可以使用 ignore_index=True 對新序列對應索引的自動標號,否則必須對 Series 指定 name屬性。 |
| assign | s = pd.Series([80, 90])<br />df1.assign(Grade=s) |
assign 返回的是一個臨時副本; [xx]會在原表的基礎上進行修改 |
三、類連接操作
| 函數(shù) | 例子 | 備注 |
|---|---|---|
| compare | df1.compare(df2) |
比較兩個表或者序列的不同處并將其匯總展示;other 和 self 分別指代傳入的參數(shù)表和被調(diào)用的表自身;值相同則會被填充為缺失值 NaN;想要完整顯示表中所有元素的比較情況,可以設置 keep_shape=True
|
| combine | def choose_min(s1, s2): print('s1', s1) print('s2',s2) s2 = s2.reindex_like(s1) res = s1.where(s1<s2, s2) res = res.mask(s1.isna()) # isna表示是否為缺失值,返回布爾序列 return res<br />df1.combine(df2, choose_min) |
讓兩個表按照一定的規(guī)則進行組合,在進行比較時會自動進行列索引的對齊。傳入函數(shù)的參數(shù)是來自兩個表的同名Series |
| df1.combine(df2, choose_min, overwrite=False) | overwrite=False可以保留 被調(diào)用表 中未出現(xiàn)在傳入的參數(shù)表中的列(例子里df1的A沒有出現(xiàn)在參數(shù)df2的表里),而不會設置未缺失值 | |
| combine_first | df1 = pd.DataFrame({'A':[1,2], 'B':[3,np.nan]}) df2 = pd.DataFrame({'A':[5,6], 'B':[7,8]}, index=[1,2]) df1.combine_first(df2) |
其功能是在對兩張表組合時,若第二張表中的值在第一張表中對應索引位置的值不是缺失狀態(tài),那么就使用第一張表的值填充。 |
練一練
- 請在上述代碼的基礎上修改,保留
df2中4個未被df1替換的相應位置原始值。
def choose_min(s1, s2):
s2 = s2.reindex_like(s1)
res = s1.where(s1<s2, s2) #在Python規(guī)定,np.nan與數(shù)字比較,都會返回False,也就是說它既比任何數(shù)字大,又比任何數(shù)字小。這里表示如果遇到數(shù)字,則會填充數(shù)字
# res = res.mask(s1.isna()) # isna表示是否為缺失值,返回布爾序列
return res
df1 = pd.DataFrame({'A':[1,2], 'B':[3,4], 'C':[5,6]})
df2 = pd.DataFrame({'B':[5,6], 'C':[7,8], 'D':[9,10]}, index=[1,2])
df1.combine(df2, choose_min)
'''
A B C D
0 NaN NaN NaN NaN
1 NaN 4.0 6.0 9.0
2 NaN 6.0 8.0 10.0
'''
- 除了
combine之外,pandas中還有一個combine_first方法,其功能是在對兩張表組合時,若第二張表中的值在第一張表中對應索引位置的值不是缺失狀態(tài),那么就使用第一張表的值填充。下面給出一個例子,請用combine函數(shù)完成相同的功能。
def choose_first(s1, s2):
s2 = s2.reindex_like(s1)
res = s1.mask(s1.isna(), s2)
return res
df1.combine(df2, choose_first)
'''
A B
0 1.0 3.0
1 2.0 7.0
2 6.0 8.0
'''
四、練習
Ex1:美國疫情數(shù)據(jù)集
現(xiàn)有美國4月12日至11月16日的疫情報表(在 /data/us_report 文件夾下),請將 New York 的 Confirmed, Deaths, Recovered, Active 合并為一張表,索引為按如下方法生成的日期字符串序列:
In [61]: date = pd.date_range('20200412', '20201116').to_series()
In [62]: date = date.dt.month.astype('string').str.zfill(2
....: ) +'-'+ date.dt.day.astype('string'
....: ).str.zfill(2) +'-'+ '2020'
....:
In [63]: date = date.tolist()
In [64]: date[:5]
Out[64]: ['04-12-2020', '04-13-2020', '04-14-2020', '04-15-2020', '04-16-2020']
import os
fileList = os.listdir("../data/us_report")
df = pd.read_csv("../data/us_report/"+fileList[0],usecols=[0,5,6,7,8])
for i in range(1,len(fileList)):
df = pd.concat([df, pd.read_csv("../data/us_report/"+fileList[i],usecols=[0,5,6,7,8])])
df = df.set_index(['Province_State'])
date = pd.date_range('20200412', '20201116').to_series()
date = date.dt.month.astype('string').str.zfill(2) +'-'+ date.dt.day.astype('string').str.zfill(2) +'-'+ '2020'
date = date.tolist()
df = df.loc['New York']
df['date'] = date
df.reset_index().drop(columns='Province_State').set_index('date')