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  199545.6               James Gosling
1  python  1991110502  199167.0            Guido van Rossum
2       C  1972021222  197233.9  Dennis MacAlistair Ritchie
3      js  1995040903  199559.5                Brendan Eich
4     php  2012092312  201269.9              Rasmus Lerdorf
5     C++  1983070316  198375.0           Bjarne Stroustrup

# --- 输出结果 data_02 ---
       编号   推出时间  月平均销售数量 主要销售区域
0  1995010302  1995134     成都
1  1991110506  2006231     北京
2  1972021222  197267     天津
3  1995040903  1995199     上海
4  2012092313  201323     深圳
5  1983070316  1983323     合肥

输出解析:通过上面的描述可以看到,我们的数据集 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  199545.6               James Gosling      134     成都
1     C  1972021222  197233.9  Dennis MacAlistair Ritchie       67     天津
2    js  1995040903  199559.5                Brendan Eich      199     上海
3   C++  1983070316  198375.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  199545.6               James Gosling    134.0     成都
1  python  1991110502  199167.0            Guido van Rossum      NaN    NaN
2       C  1972021222  197233.9  Dennis MacAlistair Ritchie     67.0     天津
3      js  1995040903  199559.5                Brendan Eich    199.0     上海
4     php  2012092312  201269.9              Rasmus Lerdorf      NaN    NaN
5     C++  1983070316  198375.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  199545.6               James Gosling      134     成都
1   NaN  1991110506  2006年   NaN                         NaN      231     北京
2     C  1972021222  197233.9  Dennis MacAlistair Ritchie       67     天津
3    js  1995040903  199559.5                Brendan Eich      199     上海
4   NaN  2012092313  2013年   NaN                         NaN       23     深圳
5   C++  1983070316  198375.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  199545.6               James Gosling    134.0     成都
1  python  1991110502  199167.0            Guido van Rossum      NaN    NaN
2       C  1972021222  197233.9  Dennis MacAlistair Ritchie     67.0     天津
3      js  1995040903  199559.5                Brendan Eich    199.0     上海
4     php  2012092312  201269.9              Rasmus Lerdorf      NaN    NaN
5     C++  1983070316  198375.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  199545.6               James Gosling  1995134       成都  
1     C  1972021222  197233.9  Dennis MacAlistair Ritchie  197267        天津
2    js  1995040903  199559.5                Brendan Eich  1995199       上海 
3   C++  1983070316  198375.0           Bjarne Stroustrup  1983323       合肥    

输出解析:这里我们指定了关键键为” 编号 “列,因此在数据匹配时,将以该列进行数据的匹配连接操作,因为两个数据集中均有” 推出时间 “列,因此会默认加上后缀 ”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  199545.6               James Gosling  1995134   成都
1     C  1972021222  197233.9  Dennis MacAlistair Ritchie  197267   天津
2    js  1995040903  199559.5                Brendan Eich  1995199   上海
3   C++  1983070316  198375.0           Bjarne Stroustrup  1983323   合肥

输出解析:通过 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  199545.6
1  python  199167.0
2       C  197233.9
3      js  199559.5
4     php  201269.9
5     C++  198375.0

print(data_04)
# --- 输出结果 data_04---
   推出时间  月平均销售数量 主要销售区域
0  1995134     成都
1  2006231     北京
2  197267     天津

print(data_05)
# --- 输出结果 ---
   推出时间  月份 发行地点
0  199512   广州
1  20062   上海
2  19724   南京
3  20175   北京

输出解析:我们构造了三个数据集,他们都有 "推出时间" 数据列,其他列名均不一样,在数据的量上也存在差异,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  199545.6      NaN    NaN   		NaN  NaN
1  python  199167.0      NaN    NaN   		NaN  NaN
2       C  197233.9      NaN    NaN   		NaN  NaN
3      js  199559.5      NaN    NaN   		NaN  NaN
4     php  201269.9      NaN    NaN   		NaN  NaN
5     C++  198375.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  199545.6  1995134.0     		成都  	199512.0   广州
1  python  199167.0  2006231.0     		北京  	20062.0    上海
2       C  197233.9  197267.0     		天津  	19724.0    南京
3      js  199559.5    NaN      NaN    		NaN  	  20175.0    北京
4     php  201269.9    NaN      NaN    		NaN    		NaN   NaN  	 NaN
5     C++  198375.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  	199545.6  1995134.0    	    成都	  	199512.0   	广州
1  python  	199167.0  2006231.0     	北京      20062.0   	上海
2       C  	197233.9  197267.0         天津      19724.0   	南京
3      js  	199559.5    NaN      NaN    	     NaN      20175.0     北京
4     php  	201269.9    NaN      NaN    	     NaN       NaN     NaN     NaN
5     C++  	198375.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  199545.6      NaN    NaN   		 NaN  NaN
1  python  199167.0      NaN    NaN  		 NaN  NaN
2       C  197233.9      NaN    NaN  		 NaN  NaN
3      js  199559.5      NaN    NaN   		 NaN  NaN
4     php  201269.9      NaN    NaN   		 NaN  NaN
5     C++  198375.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  199545.6  1995134    	 成都  		199512   广州
1  python  199167.0  2006231     	 北京  		20062   上海
2       C  197233.9  197267     	 天津  		19724   南京
# 输出解析:这里设置了在横向上合并列数据,合并方式为 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  19951  19912  19723  19954  20125  19830  19951  20062  19720  19951  20062  19723  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  199545.6  1995134.0     成都  199512.0   广州
1  python  199167.0  2006231.0     北京  20062.0   上海
2       C  197233.9  197267.0     天津  19724.0   南京
3      js  199559.5    NaN      NaN    NaN  20175.0   北京
4     php  201269.9    NaN      NaN    NaN    NaN   NaN  NaN
5     C++  198375.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  199545.6  1995134.0   成都  199512.0   广州
1  python  199167.0  2006231.0   北京  20062.0   上海
2       C  197233.9  197267.0   天津  19724.0   南京
3      js  199559.5    NaN    NaN  NaN  20175.0   北京
4     php  201269.9    NaN    NaN  NaN    NaN   NaN  NaN
5     C++  198375.0    NaN    NaN  NaN    NaN   NaN  NaN  

输出解析:这里通过 ignore_index 参数设置的对比,可以看到在列索引上的索引值的变化。

4. 小结

本节课程我们主要学习了 Pandas 对多个数据集之间的连接和合并操作,对数据的拼接和扩展有重要的帮助,主要涉及到了两个操作函数以及每个操作函数中常用的参数意义。本节课程的重点如下:

  • merge () 函数的适用场景,以及该函数常用的参数设置;
  • concat () 函数的适用场景,以及该函数常用的参数设置。

图片描述