Pandas 數據的連接拼合
1. 前言
上一小節我們學習了 Pandas 庫的算術運算,主要包括加法 add (),減法 sub (),乘法 mul () 和除法 div () 運算,以及每個操作中應該注意的事項,日常數據處理中,除了數據集之間的算術運算,我們有時候還需要像數據庫查詢那樣進行數據的連接和合并操作,為進一步的數據分析做好鋪墊。那作為強大的數據處理分析庫 Pandas 中有沒有專門提供數據集之間進行數據連接或合并的操作呢?
本節課我們將一起學習 Pandas 庫對于數據連接和合并的操作,主要涉及兩個操作函數 merge () 和 concat () ,接下來我們將詳細的學習數據合并和連接的具體操作內容。
2. 數據的連接操作
Pandas 中我們有時候需要將兩個數據集的數據進行連接,根據一個或多個鍵進行數據的連接,返回一個新的數據集供進一步的數據分析。針對數據連接操作,Panda 庫中提供了 merge () 函數進行操作。
在講解函數功能之前,我們這里準備了兩個 Excel 數據,數據內容分別如下圖:
數據文件:execl 數據 demo01.xlsx
數據文件:execl 數據 demo02.xlsx
我們通過 Pandas 進行數據解析:
# 導入pandas包
import pandas as pd
data_path_01="C:/Users/13965/Documents/myFuture/IMOOC/pandasCourse-progress/data_source/第14小節/execl數據demo01.xlsx"
data_path_02="C:/Users/13965/Documents/myFuture/IMOOC/pandasCourse-progress/data_source/第14小節/execl數據demo02.xlsx"
# 解析數據
data_01 = pd.read_excel(data_path_01)
data_02 = pd.read_excel(data_path_02)
print(data_01)
print(data_02)
# --- 輸出結果 data_01 ---
編程語言 編號 推出時間 價格 主要創始人
0 java 1995010302 1995年 45.6 James Gosling
1 python 1991110502 1991年 67.0 Guido van Rossum
2 C 1972021222 1972年 33.9 Dennis MacAlistair Ritchie
3 js 1995040903 1995年 59.5 Brendan Eich
4 php 2012092312 2012年 69.9 Rasmus Lerdorf
5 C++ 1983070316 1983年 75.0 Bjarne Stroustrup
# --- 輸出結果 data_02 ---
編號 推出時間 月平均銷售數量 主要銷售區域
0 1995010302 1995年 134 成都
1 1991110506 2006年 231 北京
2 1972021222 1972年 67 天津
3 1995040903 1995年 199 上海
4 2012092313 2013年 23 深圳
5 1983070316 1983年 323 合肥
輸出解析:通過上面的描述可以看到,我們的數據集 data_01 和 data_02 他們都有 “編號” 和 “推出時間” 這兩列,對應這兩列兩個數據集中有相同的數據,也有不同數據。
2.1 merge () 函數
該函數提供了豐富的參數,靈活的設置數據的連接方式,下面我們列舉了該函數幾個常用的參數。
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 數據集 |
right | 連接 |
how | 匹配方式的設置,有 inner,left,right 和 outer 四種模式,默認是 inner 模式 |
on | 指定連接鍵 |
suffixes | 傳入元祖,設置重疊列的索引名的后綴,默認是(‘x’,‘y’) |
1. how 參數
該參數有四個值:
- inner:是默認的匹配方式,根據兩個表的交集部分進行匹配連接;
- left:以左邊的數據表為基礎,匹配右邊的數據表,匹配不到的通過 NaN 進行填充;
- right:以右邊的數據表為基礎,匹配左邊的數據表,匹配不到的通過 NaN 進行填充;
- outer:將兩個數據表連接匯總成一個表,有匹配的展示結果,沒有匹配的填充 NaN。
下面我們通過代碼程序詳細的演示一下四種模式的區別:
# data_01 和 data_02 是從兩個excel表中解析出的數據集
# merge 函數,默認的 how = “inner”
data_res=pd.merge(data_01,data_02,how="inner")
print(data_res)
# --- 輸出結果 ---
編程語言 編號 推出時間 價格 主要創始人 月平均銷售數量 主要銷售區域
0 java 1995010302 1995年 45.6 James Gosling 134 成都
1 C 1972021222 1972年 33.9 Dennis MacAlistair Ritchie 67 天津
2 js 1995040903 1995年 59.5 Brendan Eich 199 上海
3 C++ 1983070316 1983年 75.0 Bjarne Stroustrup 323 合肥
輸出解析:默認的 inner 匹配方式,會通過兩個數據集對應的列索引進行數據的匹配,尋找兩個數據集中在 “編號” 和 “推出時間” 上匹配的數據進行連接。因為兩個數據集在 “編號” 和 “推出時間” 上,只有四個共同數據,通過 inner 方式匹配,結果只有四行數據。
# data_01 和 data_02 是從兩個excel表中解析出的數據集
# merge 函數, how = “left”
data_res=pd.merge(data_01,data_02,how="left")
print(data_res)
# --- 輸出結果 ---
編程語言 編號 推出時間 價格 主要創始人 月平均銷售數量 主要銷售區域
0 java 1995010302 1995年 45.6 James Gosling 134.0 成都
1 python 1991110502 1991年 67.0 Guido van Rossum NaN NaN
2 C 1972021222 1972年 33.9 Dennis MacAlistair Ritchie 67.0 天津
3 js 1995040903 1995年 59.5 Brendan Eich 199.0 上海
4 php 2012092312 2012年 69.9 Rasmus Lerdorf NaN NaN
5 C++ 1983070316 1983年 75.0 Bjarne Stroustrup 323.0 合肥
輸出解析:left 匹配方式,是以左側數據集的連接鍵值為標準,通過連接鍵將右邊的數據集進行連接,如果數據在連接鍵上相匹配,就把數據連接進來,如果左側數據連接鍵的值沒有找到右側與之對應的數據,就在右側數據填充 NaN 。
# data_01 和 data_02 是從兩個excel表中解析出的數據集
# merge 函數, how = “right”
data_res=pd.merge(data_01,data_02,how="right")
print(data_res)
# --- 輸出結果 ---
編程語言 編號 推出時間 價格 主要創始人 月平均銷售數量 主要銷售區域
0 java 1995010302 1995年 45.6 James Gosling 134 成都
1 NaN 1991110506 2006年 NaN NaN 231 北京
2 C 1972021222 1972年 33.9 Dennis MacAlistair Ritchie 67 天津
3 js 1995040903 1995年 59.5 Brendan Eich 199 上海
4 NaN 2012092313 2013年 NaN NaN 23 深圳
5 C++ 1983070316 1983年 75.0 Bjarne Stroustrup 323 合肥
輸出解析:right 匹配方式,是以右側數據集的連接鍵值為標準,通過連接鍵將左側的數據集進行連接,如果在連接鍵上左側數據和右側數據相匹配,就把左側的數據連接進來,右側數據連接鍵上數據左側數據沒有與之匹配的數據,則以 NaN 進行填充。
# data_01 和 data_02 是從兩個excel表中解析出的數據集
# merge 函數, how = “outer”
data_res=pd.merge(data_01,data_02,how="outer")
print(data_res)
# --- 輸出結果 ---
編程語言 編號 推出時間 價格 主要創始人 月平均銷售數量 主要銷售區域
0 java 1995010302 1995年 45.6 James Gosling 134.0 成都
1 python 1991110502 1991年 67.0 Guido van Rossum NaN NaN
2 C 1972021222 1972年 33.9 Dennis MacAlistair Ritchie 67.0 天津
3 js 1995040903 1995年 59.5 Brendan Eich 199.0 上海
4 php 2012092312 2012年 69.9 Rasmus Lerdorf NaN NaN
5 C++ 1983070316 1983年 75.0 Bjarne Stroustrup 323.0 合肥
6 NaN 1991110506 2006年 NaN NaN 231.0 北京
7 NaN 2012092313 2013年 NaN NaN 23.0 深圳
輸出解析:outer 匹配方式,是以連接鍵為標準,將左右兩邊的數據集進行連接,如果連接鍵存中兩個數據集存在匹配的數據,則把左右數據進行連接,如果有一個數據集不存在匹配數據,則用 NaN 進行填充。
2. on 參數
該參數用于指定數據集的連接鍵,默認的是兩個數據集中共有的列索引,就像我們上面的 data_01 和 data_02 數據集,他們都有 “編號” 和 “推出時間” 列,因此這兩列就是默認的連接鍵。當然我們也可以用 on 參數指定其中的一列為連接鍵,如下代碼演示:
# data_01 和 data_02 是從兩個excel表中解析出的數據集
# merge 函數, on = “編號”
data_res=pd.merge(data_01,data_02,on=["編號"])
print(data_res)
# --- 輸出結果 ---
編程語言 編號 推出時間_x 價格 主要創始人 推出時間_y 月平均銷售數量 主要銷售區域
0 java 1995010302 1995年 45.6 James Gosling 1995年 134 成都
1 C 1972021222 1972年 33.9 Dennis MacAlistair Ritchie 1972年 67 天津
2 js 1995040903 1995年 59.5 Brendan Eich 1995年 199 上海
3 C++ 1983070316 1983年 75.0 Bjarne Stroustrup 1983年 323 合肥
輸出解析:這里我們指定了關鍵鍵為” 編號 “列,因此在數據匹配時,將以該列進行數據的匹配連接操作,因為兩個數據集中均有” 推出時間 “列,因此會默認加上后綴 ”x“,”y“ 作為區分,當然后面我們會講到對后綴的修改操作。
Tips:在這里我們需要注意指定連接鍵時傳入的是列表數據,可以是多個數據列,但一定要是連接數據集中都有的列索引,否則會報錯 KeyError ,如下面代碼所示。
# data_01 和 data_02 是從兩個excel表中解析出的數據集
# merge 函數, on = “主要創始人”
data_res=pd.merge(data_01,data_02,on=["主要創始人"])
print(data_res)
# --- 輸出結果 ---
……
1561 values = self.axes[axis].get_level_values(key)._values
1562 else:
-> 1563 raise KeyError(key)
1564
1565 # Check for duplicates
KeyError: '主要創始人'
輸出解析:這里可以看到,我們指定了連接鍵是 “主要創始人”,并不是兩個數據集中都有的列索引,因此會報錯。
3. suffixes 參數
該參數用于指定連接后數據集中重復列索引的后綴,默認的是(‘x’,‘y’):
# data_01 和 data_02 是從兩個excel表中解析出的數據集
# merge 函數,suffixes
data_res=pd.merge(data_01,data_02,on=["編號"],suffixes=("AA","BB") )
print(data_res)
# --- 輸出結果 ---
編程語言 編號 推出時間AA 價格 主要創始人 推出時間BB 月平均銷售數量 主要銷售區域
0 java 1995010302 1995年 45.6 James Gosling 1995年 134 成都
1 C 1972021222 1972年 33.9 Dennis MacAlistair Ritchie 1972年 67 天津
2 js 1995040903 1995年 59.5 Brendan Eich 1995年 199 上海
3 C++ 1983070316 1983年 75.0 Bjarne Stroustrup 1983年 323 合肥
輸出解析:通過 suffixes 參數指定重復列索引值所添加的后綴值,通過輸出結果可以看出 “推出時間” 分別加上上 AA, BB 的后綴。
3. 數據的合并操作
除了連接數據集,我們有時候需要對數據集在行或者列上進行數據的拓展,這就要涉及到多個數據集的合并操作了,Pandas 中提供了 concat () 函數用于數據集的合并操作。
同樣的在正式講解該函數使用之前,我們先準備一下數據源。
數據文件:execl 數據 demo03.xlsx
數據文件:execl 數據 demo04.xlsx
數據文件:execl 數據 demo05.xlsx
通過 Pandas 將數據解析出來,數據對象分別為:data_03 ,data_04 ,data_05
# 導入pandas包
import pandas as pd
data_path_03="C:/Users/13965/Documents/myFuture/IMOOC/pandasCourse-progress/data_source/第14小節/execl數據demo03.xlsx"
data_path_04="C:/Users/13965/Documents/myFuture/IMOOC/pandasCourse-progress/data_source/第14小節/execl數據demo04.xlsx"
data_path_05="C:/Users/13965/Documents/myFuture/IMOOC/pandasCourse-progress/data_source/第14小節/execl數據demo05.xlsx"
# 解析數據
data_03 = pd.read_excel(data_path_03)
data_04 = pd.read_excel(data_path_04)
data_05 = pd.read_excel(data_path_05)
print(data_03)
# --- 輸出結果 data_03 ---
編程語言 推出時間 價格
0 java 1995年 45.6
1 python 1991年 67.0
2 C 1972年 33.9
3 js 1995年 59.5
4 php 2012年 69.9
5 C++ 1983年 75.0
print(data_04)
# --- 輸出結果 data_04---
推出時間 月平均銷售數量 主要銷售區域
0 1995年 134 成都
1 2006年 231 北京
2 1972年 67 天津
print(data_05)
# --- 輸出結果 ---
推出時間 月份 發行地點
0 1995年 12 廣州
1 2006年 2 上海
2 1972年 4 南京
3 2017年 5 北京
輸出解析:我們構造了三個數據集,他們都有 "推出時間" 數據列,其他列名均不一樣,在數據的量上也存在差異,data_03 有 6 條數據,data_04 有 3 條數據,data_05 有 4 條數據。
3.1 concat () 函數
對于多個數據集的合并操作,concat () 函數提供了豐富的設置參數,滿足我們靈活的合并需要,這里我們列舉幾個常用的參數進行詳細講解。
pd.concat(objs, axis='0', join:'outer', ignore_index: 'False', keys='None', levels='None', names='None', verify_integrity: 'False', sort: 'False', copy:'True')
參數名 | 說明 |
---|---|
objs | 要合并的數據列表,可以是 Series、 DataFrame |
axis | 合并的方向,axis=0 縱向合并 (默認),axis=1 橫向合并 |
join | 數據合并的方式,包含 inner 和 outer 兩種,默認是 outer |
ignore_index | 忽略合并方向上軸的索引值,從 0 開始重新進行索引值排序,默認為 ignore_index=False |
下面我們通過代碼程序進行詳細學習這些參數的使用。
1. axis 參數
該參數用于設置數據合并的方向。
# data_03,data_04,data_05 是上面從三個excel表中解析出的數據集
# concat 函數,axis=0 是縱向上按行合并。
data_res=pd.concat([data_03,data_04,data_05],axis=0)
print(data_res)
# --- 輸出結果 ---
編程語言 推出時間 價格 月平均銷售數量 主要銷售區域 月份 發行地點
0 java 1995年 45.6 NaN NaN NaN NaN
1 python 1991年 67.0 NaN NaN NaN NaN
2 C 1972年 33.9 NaN NaN NaN NaN
3 js 1995年 59.5 NaN NaN NaN NaN
4 php 2012年 69.9 NaN NaN NaN NaN
5 C++ 1983年 75.0 NaN NaN NaN NaN
0 NaN 1995年 NaN 134.0 成都 NaN NaN
1 NaN 2006年 NaN 231.0 北京 NaN NaN
2 NaN 1972年 NaN 67.0 天津 NaN NaN
0 NaN 1995年 NaN NaN NaN 12.0 廣州
1 NaN 2006年 NaN NaN NaN 2.0 上海
2 NaN 1972年 NaN NaN NaN 4.0 南京
3 NaN 2017年 NaN NaN NaN 5.0 北京
# 輸出解析:通過設置 axis=0 在縱向上合并數據,總的行數據量是3個數據集的總和,擴充了行數據。
# concat 函數,axis=1 設置在橫向上合并。
data_res=pd.concat([data_03,data_04,data_05],axis=1)
print(data_res)
# --- 輸出結果 ---
編程語言 推出時間 價格 推出時間 月平均銷售數量 主要銷售區域 推出時間 月份 發行地點
0 java 1995年 45.6 1995年 134.0 成都 1995年 12.0 廣州
1 python 1991年 67.0 2006年 231.0 北京 2006年 2.0 上海
2 C 1972年 33.9 1972年 67.0 天津 1972年 4.0 南京
3 js 1995年 59.5 NaN NaN NaN 2017年 5.0 北京
4 php 2012年 69.9 NaN NaN NaN NaN NaN NaN
5 C++ 1983年 75.0 NaN NaN NaN NaN NaN NaN
# 輸出解析:通過設置 axis=1 在橫向上合并數據,總的列數據量是3個數據集的總和,擴充了列數據。
2. join 參數
該參數設置數據集合并的方式,有兩個值:
- inner:數據集之間的交集,行合并時取列索引值的相同的數據,列合并時取行索引值相同的數據;
- outer:取數據集之間的并集,沒有數據的用 NaN 進行填充,默認是這種合并方式。
# data_03,data_04,data_05 是上面從三個excel表中解析出的數據集
# concat 函數,axis=1,join="outer" 設置合并的方式。
data_res=pd.concat([data_03,data_04,data_05],axis=1,join="outer")
print(data_res)
# --- 輸出結果 ---
編程語言 推出時間 價格 推出時間 月平均銷售數量 主要銷售區域 推出時間 月份 發行地點
0 java 1995年 45.6 1995年 134.0 成都 1995年 12.0 廣州
1 python 1991年 67.0 2006年 231.0 北京 2006年 2.0 上海
2 C 1972年 33.9 1972年 67.0 天津 1972年 4.0 南京
3 js 1995年 59.5 NaN NaN NaN 2017年 5.0 北京
4 php 2012年 69.9 NaN NaN NaN NaN NaN NaN
5 C++ 1983年 75.0 NaN NaN NaN NaN NaN NaN
# 輸出解析:這里設置在橫向上合并列數據,合并方式為 outer ,所以將所有數據集的行索引取了并集,data_03 的行索引值為0-5,data_04 的行索引值為0-2,data_5 的行索引值為0-3,他們的并集就是 data_03 的從0到5,對于 data_04 和 data_05 在對應的行索引上不存在數據的,則以 NaN 進行填充。
# concat 函數,axis=0,join="outer" 設置合并的方式。
data_res=pd.concat([data_03,data_04,data_05],axis=0,join="outer")
print(data_res)
# --- 輸出結果 ---
編程語言 推出時間 價格 月平均銷售數量 主要銷售區域 月份 發行地點
0 java 1995年 45.6 NaN NaN NaN NaN
1 python 1991年 67.0 NaN NaN NaN NaN
2 C 1972年 33.9 NaN NaN NaN NaN
3 js 1995年 59.5 NaN NaN NaN NaN
4 php 2012年 69.9 NaN NaN NaN NaN
5 C++ 1983年 75.0 NaN NaN NaN NaN
0 NaN 1995年 NaN 134.0 成都 NaN NaN
1 NaN 2006年 NaN 231.0 北京 NaN NaN
2 NaN 1972年 NaN 67.0 天津 NaN NaN
0 NaN 1995年 NaN NaN NaN 12.0 廣州
1 NaN 2006年 NaN NaN NaN 2.0 上海
2 NaN 1972年 NaN NaN NaN 4.0 南京
3 NaN 2017年 NaN NaN NaN 5.0 北京
# 輸出解析: 這里設置了在縱向上的行合并,合并方式為 outer,在列索引上取了并集,為{“編程語言”,“推出時間”,“價格”,“月平均銷售數量”,“主要銷售區域”,“月份”,“發行地點”},合并行中如果不存在對應列的數據,則以 NaN 進行填充。
# concat 函數,axis=1,join="inner" 設置合并的方式。
data_res=pd.concat([data_03,data_04,data_05],axis=1,join="inner")
print(data_res)
# --- 輸出結果 ---
編程語言 推出時間 價格 推出時間 月平均銷售數量 主要銷售區域 推出時間 月份 發行地點
0 java 1995年 45.6 1995年 134 成都 1995年 12 廣州
1 python 1991年 67.0 2006年 231 北京 2006年 2 上海
2 C 1972年 33.9 1972年 67 天津 1972年 4 南京
# 輸出解析:這里設置了在橫向上合并列數據,合并方式為 inner ,在行索引值中去交集,data_03 的行索引值為0-5,data_04 的行索引值為0-2,data_5 的行索引值為0-3,他們的交集也就是0到2,可以看到輸出結果合并了列,取了三行數據。
# concat 函數,axis=0,join="inner" 設置合并的方式。
data_res=pd.concat([data_03,data_04,data_05],axis=0,join="inner")
print(data_res)
# --- 輸出結果 ---
推出時間
0 1995年
1 1991年
2 1972年
3 1995年
4 2012年
5 1983年
0 1995年
1 2006年
2 1972年
0 1995年
1 2006年
2 1972年
3 2017年
# 輸出解析:通過設置在行上進行數據合并,用的 inner 方式合并,在列的數據上,他們的交集只有“推出時間”,通過輸出可以看到效果。
通過上面的代碼演示可以看到,因為 outer 取得是并集,合并結果中可能會出現 NaN 的填充數據,而 inner 取的是交集,合并數據結果集中不會出現 NaN 的缺失數據。
3. ignore_index 參數
該參數可以設置在合并方向上的索引值自動生成,從 0 開始的整數序列。
# data_03,data_04,data_05 是上面從三個excel表中解析出的數據集
# concat 函數,ignore_index 重新生成索引序列。
data_res=pd.concat([data_03,data_04,data_05],axis=1,ignore_index=False)
print(data_res)
# --- 輸出結果 ignore_index=False(默認的值)---
編程語言 推出時間 價格 推出時間 月平均銷售數量 主要銷售區域 推出時間 月份 發行地點
0 java 1995年 45.6 1995年 134.0 成都 1995年 12.0 廣州
1 python 1991年 67.0 2006年 231.0 北京 2006年 2.0 上海
2 C 1972年 33.9 1972年 67.0 天津 1972年 4.0 南京
3 js 1995年 59.5 NaN NaN NaN 2017年 5.0 北京
4 php 2012年 69.9 NaN NaN NaN NaN NaN NaN
5 C++ 1983年 75.0 NaN NaN NaN NaN NaN NaN
data_res=pd.concat([data_03,data_04,data_05],axis=1,ignore_index=True)
print(data_res)
# --- 輸出結果 ignore_index=True ---
0 1 2 3 4 5 6 7 8
0 java 1995年 45.6 1995年 134.0 成都 1995年 12.0 廣州
1 python 1991年 67.0 2006年 231.0 北京 2006年 2.0 上海
2 C 1972年 33.9 1972年 67.0 天津 1972年 4.0 南京
3 js 1995年 59.5 NaN NaN NaN 2017年 5.0 北京
4 php 2012年 69.9 NaN NaN NaN NaN NaN NaN
5 C++ 1983年 75.0 NaN NaN NaN NaN NaN NaN
輸出解析:這里通過 ignore_index 參數設置的對比,可以看到在列索引上的索引值的變化。
4. 小結
本節課程我們主要學習了 Pandas 對多個數據集之間的連接和合并操作,對數據的拼接和擴展有重要的幫助,主要涉及到了兩個操作函數以及每個操作函數中常用的參數意義。本節課程的重點如下:
- merge () 函數的適用場景,以及該函數常用的參數設置;
- concat () 函數的適用場景,以及該函數常用的參數設置。