点击上方“Python爬虫与数据挖掘”,进行关注
回复“书籍”即可获赠Python从入门到进阶共10本电子书
今
日
鸡
汤
为有牺牲多壮志,敢教日月换新天。
「数仓宝贝库」,带你学数据!
导读:在数据分析过程中,有时候需要将不同的数据文件进行合并处理。本文主要介绍三种数据合并方法。
Pandas提供了多功能、高性能的内存连接操作,本质上类似于SQL等关系数据库,比如,merge、join、concat等方法可以方便地将具有多种集合逻辑的Series或DataFrame数据合并、拼接在一起,用于实现索引和关系代数功能。
merge方法主要基于数据表共同的列标签进行合并,
join方法主要基于数据表的index标签进行合并,
concat方法是对数据表进行行拼接或列拼接。
01
merge方法
merge方法的主要应用场景是针对存在同一个或多个相同列标签(主键)的包含不同特征的两个数据表,通过主键的连接将这两个数据表进行合并。其语法格式如下:
result=pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False,…)
常用的参数含义说明如下。
left/right
:参与合并的左/右侧的Series或DataFrame对象(数据表)。how
:数据合并的方式。默认为'inner'
,表示内连接(交集),'outer'
表示外连接(并集),'left'
表示基于左侧数据列的左连接,'right'
表示基于右侧数据列的右连接。on
:指定用于连接的列标签,可以是一个列标签,也可以是一个包含多个列标签的列表。默认为left
和right
中相同的列标签。left_on/right_on
:当left
和right
中合并的列标签名称不同时,用来分别指定左/右两表合并的列标签。left_index/right_index
:布尔类型,默认为False
。当设置为True
时,则以左/右侧的行标签作为连接键。
下面通过代码清单1演示merge方法的用法。
代码清单1 merge方法的用法示例
1 import pandas as pd
2 left = pd.DataFrame({'key1': ['K0', 'K1', 'K2'],'key2': ['K0', 'K1', 'K0'],'A': ['A0', 'A1', 'A2'],'B': ['B0', 'B1', 'B2']})
3 right = pd.DataFrame({'key1': ['K0', 'K1', 'K2'],'key2': ['K0', 'K0','K0'],'C': ['C0', 'C1', 'C2',], 'D': ['D0', 'D1', 'D2']})
4 print('left:\n',left)
5 print('right:\n',right)
6 result1 = pd.merge(left, right, on='key1') # 内连接
7 print('根据key1列将left和right内连接:\n',result1)
8 result2 = pd.merge(left, right, on=['key1', 'key2'])
9 print('根据key1和key2列将left和right内连接:\n',result2)
10 result3 = pd.merge(left, right, how='outer', on=['key1', 'key2'])
11 print('根据key1和key2列将left和right外连接:\n',result3)
12 result4 = pd.merge(left, right, how='left', on=['key1', 'key2'])
13 print('根据key1和key2列将left和right左连接:\n',result4)
14 result5 = pd.merge(left, right, how='right', on=['key1', 'key2'])
15 print('根据key1和key2列将left和right右连接:\n',result5)
程序执行结束后,输出结果如下:
left:
key1 key2 A B
0 K0 K0 A0 B0
1 K1 K1 A1 B1
2 K2 K0 A2 B2
right:
key1 key2 C D
0 K0 K0 C0 D0
1 K1 K0 C1 D1
2 K2 K0 C2 D2
根据key1列将left和right内连接:
key1 key2_x A B key2_y C D
0 K0 K0 A0 B0 K0 C0 D0
1 K1 K1 A1 B1 K0 C1 D1
2 K2 K0 A2 B2 K0 C2 D2
根据key1和key2列将left和right内连接:
key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K2 K0 A2 B2 C2 D2
根据key1和key2列将left和right外连接:
key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K1 K1 A1 B1 NaN NaN
2 K2 K0 A2 B2 C2 D2
3 K1 K0 NaN NaN C1 D1
根据key1和key2列将left和right左连接:
key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K1 K1 A1 B1 NaN NaN
2 K2 K0 A2 B2 C2 D2
根据key1和key2列将left和right右连接:
key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K2 K0 A2 B2 C2 D2
2 K1 K0 NaN NaN C1 D1
下面对代码清单1中的代码做简要说明。
第2行代码通过字典创建了一个3行4列的DataFrame对象
left
,如第4行print
函数的输出结果所示。第3行代码通过字典创建了一个3行4列的DataFrame对象
right
,如第5行print
函数的输出结果所示。第6行代码通过
merge
方法将left
与right
合并,on='key1'
指定根据列标签key1
进行合并,合并方式默认为内连接,合并后的结果为一个3行7列的DataFrame对象,如第7行print
函数的输出结果所示。内连接是取
left
和right
的交集,由于left
和right
中key1
列的数据完全相同,因此保留了两个数据表中的所有行。除key1
之外,left
和right
中还存在另一个相同的列标签key2
,为了在合并后的对象中加以区分,Pandas自动将left
中的key2
重命名为key2_x
,right
中的key2
重命名为key2_y
。第8行代码通过
merge
方法将left
与right
合并,on=['key1', 'key2']
指定根据列标签key1
和key2
进行合并,合并方式默认为内连接,合并后的结果为一个2行6列的DataFrame对象,如第9行print
函数的输出结果所示。由于
left
和right
中key2
列数据不完全相同,因此要取left
和right
的交集,只将['key1', 'key2']
两列组合数据完全相同的行进行合并,即将第1行和第3行合并,并自动调整合并后DataFrame对象的index
。第10行代码通过
merge
方法将left
与right
合并,on=['key1', 'key2']
指定根据列标签key1
和key2
进行合并,how='outer'
指定合并方式为外连接,合并后的结果为一个4行6列的DataFrame对象,如第11行print
函数的输出结果所示。外连接是取
left
和right
的并集,['key1', 'key2']
两列组合数据对应的行都会进行合并。对于left
和right
中没有的列标签,要在对应位置设置NA,并自动调整合并后DataFrame对象的index
。第12行代码通过
merge
方法将left
与right
合并,on=['key1', 'key2']
指定根据列标签key1
和key2
进行合并,how='left'
指定合并方式为左连接,合并后的结果为一个3行6列的DataFrame对象,如第13行print
函数的输出结果所示。左连接是保留
left
的所有数据,只取right
中与left
的['key1', 'key2']
组合数据相同的行进行合并。对于left
中没有的列标签,要在对应位置设置NA,并自动调整合并后DataFrame对象的index
。第14行代码通过
merge
方法将left
与right
合并,on=['key1', 'key2']
指定根据列标签key1
和key2
进行合并,how='right'
指定合并方式为右连接,合并后的结果为一个3行6列的DataFrame对象,如第15行print
函数输出结果所示。右连接是保留
right
的所有数据,只取left
中与right的['key1', 'key2']
组合数据相同的行进行合并。对于right
中没有的列标签,要在对应位置设置NA,并自动调整合并后DataFrame对象的index
。
Tips
1)使用merge
合并两个数据表,如果左侧或右侧的数据表中没有某个列标签,则连接表中对应的值将设置为NA。
2)merge
方法不会修改原始数据表,而是生成一个合并后的副本。
02
join方法
Pandas还提供了一种基于index标签的快速合并方法——join方法。join连接数据的方法与merge一样,包括内连接、外连接、左连接和右连接。其语法格式如下:
result = data.join(other, on=None, how='left',…)
data
是一个Series或DataFrame对象(数据表)。other
:要合并的Series或DataFrame对象(数据表)。on
:可以是一个data
中的列标签,也可以是一个包含多个data
列标签的列表,表示other
要在data
的特定列上对齐。在实际应用中,如果other
的index
的值与data某一列的值相等,可以通过将other
的index
和data
中的特定列对齐进行合并,这类似于Excel中的VLOOKUP操作。how
:数据合并的方式。默认为'left'
,表示左连接,基于data
的index
标签进行连接;'right'
表示右连接,基于other
的index
标签进行连接;'inner'
表示内连接(交集);'outer'
表示外连接(并集)。
下面通过代码清单2演示join方法的用法。
代码清单2 join方法的用法示例
1 import pandas as pd
2 left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],'B': ['B0', 'B1', 'B2']}, index=['K0', 'K1', 'K2'])
3 right = pd.DataFrame({'C': ['C0', 'C2', 'C3'], 'D': ['D0', 'D2', 'D3']}, index=['K0', 'K2', 'K3'])
4 print('left:\n',left)
5 print('right:\n',right)
6 result1 = left.join(right)
7 print('left和right左连接(join方法):\n',result1)
8 result2 = pd.merge(left, right, left_index=True, right_index=True, how='left')
9 print('left和right左连接(merge方法):\n',result2)
10 result3 = left.join(right, how='inner')
11 print('left和right内连接(join方法):\n',result3)
12 result4 = pd.merge(left, right, left_index=True, right_index=True, how='inner')
13 print('left和right内连接(merge方法):\n',result4)
14 left2 = pd.DataFrame({'key': ['K0', 'K1', 'K0'],'A': ['A0', 'A1', 'A2'],'B': ['B0', 'B1', 'B2']})
15 print('left2:\n',left2)
16 result5 = left2.join(right,on='key')
17 print('left2和right左连接(join方法):\n',result5)
18 result6= pd.merge(left2, right, left_on='key', right_index=True, how='left');
19 print('left2和right左连接(merge方法):\n',result6)
程序执行结束后,输出结果如下:
left:
A B
K0 A0 B0
K1 A1 B1
K2 A2 B2
right:
C D
K0 C0 D0
K2 C2 D2
K3 C3 D3
left和right左连接(join方法):
A B C D
K0 A0 B0 C0 D0
K1 A1 B1 NaN NaN
K2 A2 B2 C2 D2
left和right左连接(merge方法):
A B C D
K0 A0 B0 C0 D0
K1 A1 B1 NaN NaN
K2 A2 B2 C2 D2
left和right内连接(join方法):
A B C D
K0 A0 B0 C0 D0
K2 A2 B2 C2 D2
left和right内连接(merge方法):
A B C D
K0 A0 B0 C0 D0
K2 A2 B2 C2 D2
left2:
key A B
0 K0 A0 B0
1 K1 A1 B1
2 K0 A2 B2
left2和right左连接(join方法):
key A B C D
0 K0 A0 B0 C0 D0
1 K1 A1 B1 NaN NaN
2 K0 A2 B2 C0 D0
left2和right左连接(merge方法):
key A B C D
0 K0 A0 B0 C0 D0
1 K1 A1 B1 NaN NaN
2 K0 A2 B2 C0 D0
下面对代码清单2中的代码做简要说明。
第2行代码通过字典创建了一个3行2列的DataFrame对象
left
,index
被设置为['K0', 'K1', 'K2']
,如第4行print
函数的输出结果所示。第3行代码通过字典创建了一个3行2列的DataFrame对象
right
,index
被设置为['K0', 'K2', 'K3']
,如第5行print
函数的输出结果所示。第6行代码通过
join
方法将left
与right
合并,合并方式默认为基于left
的左连接,合并后的结果为一个3行4列的DataFrame对象,如第7行print
函数的输出结果所示。第8行代码通过
merge
方法将left
与right
合并,合并方式和结果与第6行代码相同,left_index和right_index
参数被设置为True,表示以left
和right
的index
行标签作为连接键,如第9行print
函数的输出结果所示。第10行代码通过
join
方法将left
与right
合并,how='inner'
指定合并方式为内连接,合并后的结果为一个2行4列的DataFrame对象,如第11行print
函数的输出结果所示。第12行代码通过
merge
方法将left
与right
合并,合并方式和结果与第10行代码相同,left_index
和right_index
参数被设置为True
,表示以left
和right
的index
行标签作为连接键,如第13行print
函数的输出结果所示。第14行代码通过字典创建了一个3行3列的DataFrame对象
left2
,没有设置index
参数,如第15行print
函数的输出结果所示。第16行代码通过
join
方法将left2
与right
合并,由于left2
与right
不具有相同的行标签,但是right
的index
与left2
的key
列有相同的数值,因此通过on='key'
指定将left2
中的key
与right
中的index
对齐,合并方式默认为左连接,合并后的结果为一个3行5列的DataFrame对象,如第17行print
函数的输出结果所示。第18行代码通过
merge
方法将left2
与right
合并,合并方式和结果与第16行代码相同,left_on='key'
表示表left
以key
列为连接键,right_index=True
表示表right
以index
行标签为连接键,how='left'
表示连接方式为左连接,如第19行print
函数的输出结果所示。
Tips
1)join方法实现的数据表合并也可以用merge方法实现,但join方法更简单、更快速。
2)join方法不会修改原始数据表,而是生成一个合并后的副本。
03
concat方法
concat方法的功能为沿着一个特定轴,对一组相同类型的Pandas对象执行连接操作。如果操作对象是DataFrame,还可以同时在其他轴上执行索引的可选集合逻辑操作(并集或交集)。concat方法接受一列或一组相同类型的对象,并通过一些可配置的处理将它们连接起来,这些处理可用于其他轴。其语法格式如下:
result=pd.concat(objs, axis=0, join='outer', ignore_index=False, keys=None,…)
常用的参数含义说明如下。
objs
是需要拼接的对象集合,一般为Series或DataFrame对象的列表或者字典。axis
表示连接的轴向,默认为0,表示纵向拼接,即基于列标签的拼接,拼接之后行数增加。axis=1
时表示横向拼接,即基于行标签的拼接,拼接之后列数增加。join
表示连接方式,默认为'outer'
,拼接方法为外连接(并集)。join='inner'
时,拼接方法为内连接(交集)。ignore_index
是布尔类型,默认为False
,表示保留连接轴上的标签。如果将其设置为True
,则不保留连接轴上的标签,而是产生一组新的标签。keys
是列表类型。如果连接轴上有相同的标签,为了区分,可以用keys在最外层定义标签的分组情况,形成连接轴上的层次化索引。
下面通过代码清单3演示concat方法的用法。
代码清单3 concat方法的用法示例
1 import pandas as pd
2 df1 = pd.DataFrame({'A':['A0','A1','A2'], 'B':['B0','B1','B2'],
'C':['C0','C1','C2'], 'D':['D0','D1','D2']}, index=[0,1,2])
3 df2 = pd.DataFrame({'A':['A3','A4', 'A5'], 'B':['B3','B4', 'B5'],'C':
['C3','C4', 'C5'], 'D':['D3','D4', 'D5']}, index=[3,4,5])
4 df3 = pd.DataFrame({'A':['A6','A7','A8'], 'B':['B6','B7','B8'],
'C':['C6','C7','C8'], 'D':['D6','D7','D8']}, index=[6,7,8])
5 df4 = pd.DataFrame({'B':['B2','B3','B6'], 'D':['D2','D3','D6'],
'F':['F2','F3','F6']}, index=[2,3,6])
6 result1 = pd.concat([df1,df2,df3])
7 print('df1、df2和df3纵向外拼接:\n',result1)
8 result2=pd.concat([df1,df2],axis=1,keys=['df1','df2'])
9 print('df1和df2横向外拼接(concat方法):\n',result2)
10 result3=df1.join(df2, how='outer',lsuffix='_df1',rsuffix='_df2')
11 print('df1和df2横向外拼接(join方法):\n',result3)
12 result4=pd.concat([df1,df3])
13 print('df1和df3纵向外拼接:\n',result4)
14 result5=pd.concat([df1,df3],ignore_index=True)
15 print('df1和df3纵向外拼接并生成新的行标签:\n',result5)
16 result6=pd.concat([result1,df4], axis=1, join='inner', keys = ['result1','df2'])
17 print('result1和df4横向内拼接:\n',result6)
程序执行结束后,输出结果如下:
df1、df2和df3纵向外拼接:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
8 A8 B8 C8 D8
df1和df2横向外拼接(concat方法):
df1 df2
A B C D A B C D
0 A0 B0 C0 D0 NaN NaN NaN NaN
1 A1 B1 C1 D1 NaN NaN NaN NaN
2 A2 B2 C2 D2 NaN NaN NaN NaN
3 NaN NaN NaN NaN A3 B3 C3 D3
4 NaN NaN NaN NaN A4 B4 C4 D4
5 NaN NaN NaN NaN A5 B5 C5 D5
df1和df2横向外拼接(join方法):
A_df1 B_df1 C_df1 D_df1 A_df2 B_df2 C_df2 D_df2
0 A0 B0 C0 D0 NaN NaN NaN NaN
1 A1 B1 C1 D1 NaN NaN NaN NaN
2 A2 B2 C2 D2 NaN NaN NaN NaN
3 NaN NaN NaN NaN A3 B3 C3 D3
4 NaN NaN NaN NaN A4 B4 C4 D4
5 NaN NaN NaN NaN A5 B5 C5 D5
df1和df3纵向外拼接:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
6 A6 B6 C6 D6
7 A7 B7 C7 D7
8 A8 B8 C8 D8
df1和df3纵向外拼接并生成新的行标签:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A6 B6 C6 D6
4 A7 B7 C7 D7
5 A8 B8 C8 D8
result1和df4横向内拼接:
A B C D B D F
2 A2 B2 C2 D2 B2 D2 F2
3 A3 B3 C3 D3 B3 D3 F3
6 A6 B6 C6 D6 B6 D6 F6
下面对代码清单3中的代码做简要说明。
第2~5行代码分别通过字典创建了4个3行4列的DataFrame对象
df1
、df2
、df3
、df4
,index
分别被设置为[0,1,2]
、[3,4,5]
、[6,7,8]
、[2,3,6]
。第6行代码通过
concat
方法将df1
、df2
和df3
拼接,采用默认的参数设置,即纵向外拼接。由于df1、df2和df3的列标签完全相等,但行标签没有重叠的部分,拼接后的结果为一个9行4列的DataFrame对象,如第7行print
函数的输出结果所示。第8行代码通过
concat
方法将df1
和df2
拼接,axis=1
表示横向拼接,拼接方式默认为外拼接。由于df1
和df2
的列标签完全相等,拼接后的列会有重复的列标签。为了便于区分,设置参数keys=['df1','df2']
在最外层定义标签的分组情况,df1
的列标签的外层索引为'df1'
,df2
的列标签的外层索引为'df2'
。拼接后的结果为一个6行8列的DataFrame对象,如第9行print
函数的输出结果所示。第10行代码通过
join
方法将df1
和df2
拼接,拼接方式与第8行代码相同。how='outer'
设置为外拼接,为了区分拼接后的对象中重复的列标签,设置lsuffix='_df1'
,指定df1
的列名加上后缀'_df1'
;设置rsuffix='_df2'
,指定df2
的列名加上后缀'_df2'
,如第11行print
函数的输出结果所示。可以看到,result3
中的元素数据与result2
相同,不同之处在于result2
采用外层索引的方式区分重复列,而result3
采用列名加后缀的方法。第12行代码通过
concat
方法将df1
和df3
拼接,采用默认的参数设置,即纵向外拼接。拼接后的结果为一个6行4列的DataFrame对象,如第13行print
函数的输出结果所示,可以看到result3
的行标签完全保留了df1
和df3
的行标签。第14行代码在第12行代码的基础上,增加了参数设置
ignore_index=True
,表示会重新生成新的整数序列作为拼接后的DataFrame对象的行标签,如第15行print
函数的输出结果所示。第16行代码通过
concat
方法将第6行代码的result1
和df4
拼接,axis=1
表示横向拼接,join='inner'
指定内拼接。拼接后的结果为一个3行7列的DataFrame对象,如第17行print
函数的输出结果所示,保留了result1
和df4
中相同的行标签。
Tips
1)在实际应用中,join方法常用于基于行标签对数据表的列进行拼接,concat方法则常用于基于列标签对数据表的行进行拼接。
2)concat方法不会修改原始数据表,而是生成一个合并后的副本。
- END -
本文摘编于《Python数据分析与应用》,经出版方授权发布。
内容简介
1、如正文所介绍的那样。
活动规则
参与方式:在下方公众号后台回复 “送书”关键字,记得是“送书”二字哈,即可参与本次的送书活动。
公布时间:2021年9月1号(周三)晚上20点
领取事宜:请小伙伴添加小助手微信: WebFighting,或者扫码添加好友。添加小助手的每一个人都可以领取一份Python学习资料,更重要的是方便联系。
注意事项:一定要留意微信消息,如果你是幸运儿就尽快在小程序中填写收货地址、书籍信息。一天之内没有填写收货信息,送书名额就转给其他人了噢,欢迎参加!
------------------- End -------------------
往期精彩文章推荐:
欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持
想加入Python学习群请在后台回复【入群】
万水千山总是情,点个【在看】行不行
/今日留言主题/
随便说一两句吧~~