第一章可前往查看:《Pandas学习笔记01-基础知识》
pandas对象中的数据可以通过一些方式进行合并: pandas.concat可以沿着一条轴将多个对象堆叠到一起; pandas.merge可根据一个或多个键将不同DataFrame中的行连接起来。
这部分,我觉得pandas官网资料介绍的太香了,直接搬运过来吧。
concat函数可以在两个维度上对数据进行拼接,默认纵向拼接(axis=0),拼接方式默认外连接(outer)。
纵向拼接通俗来讲就是按行合并,横向拼接通俗来讲就是按列合并; 外连接通俗来说就是取所有的表头字段或索引字段,内连接通俗来说就是只取各表都有的表头字段或索引字段。
先简单看个例子吧~
In [1]: df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
...: 'B': ['B0', 'B1', 'B2', 'B3'],
...: 'C': ['C0', 'C1', 'C2', 'C3'],
...: 'D': ['D0', 'D1', 'D2', 'D3']},
...: index=[0, 1, 2, 3])
In [2]: df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
...: 'B': ['B4', 'B5', 'B6', 'B7'],
...: 'C': ['C4', 'C5', 'C6', 'C7'],
...: 'D': ['D4', 'D5', 'D6', 'D7']},
...: index=[4, 5, 6, 7])
In [3]: df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
...: 'B': ['B8', 'B9', 'B10', 'B11'],
...: 'C': ['C8', 'C9', 'C10', 'C11'],
...: 'D': ['D8', 'D9', 'D10', 'D11']},
...: index=[8, 9, 10, 11])
In [4]: df = [df1,df2,df3]
In [5]: result = pd.concat(df)
合并演示
pd.concat(objs, axis=0, join='outer', ignore_index=False, keys=None,levels=None, names=None, verify_integrity=False, copy=True)
objs:需要用于连接合并的对象列表 axis:连接的方向,默认为0(按行),按列为1 join:连接的方式,默认为outer,可选inner只取交集 ignore_index:合并后的数据索引重置,默认为False,可选True keys:列表或数组,也可以是元组的数组,用来构造层次结构索引 levels:指定用于层次化索引各级别上的索引,在有keys值时 names:用于创建分层级别名称,在有keys和levels时 verify_integrity:检查连接对象中新轴是否重复,若是则异常,默认为False允许重复 copy:默认为True,如果是False,则不会复制不必要的可以提高效率
In [6]: result = pd.concat(df, keys=['x', 'y', 'z'])
设置keys值 我们还可以通过字典形式传递keys参数(以下代码结果 和上述一致):
In [7]: pieces = {'x': df1, 'y': df2, 'z': df3}
In [8]: result = pd.concat(pieces)
我们还可以指定keys值进行数据合并:
In [9]: result = pd.concat(pieces, keys=['z', 'y'])
指定keys值数据合并 以上我们可以看到,设定keys值后,合并后的数据多了一层索引,我们可以直接通过这一层索引选择整块数据:
In [10]: result.loc['y']
Out[11]:
A B C D
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
默认情况下,join='outer',合并时索引全部保留,对于不存在值的部分会默认赋NaN。
In [12]: df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],
...: 'D': ['D2', 'D3', 'D6', 'D7'],
...: 'F': ['F2', 'F3', 'F6', 'F7']},
...: index=[2, 3, 6, 7])
In [13]: result = pd.concat([df1, df4], axis=1,sort=False)
按列合并 对于按照列合并数据时,如果我们希望只保留第一份数据下的索引,可以通过如下两种方式实现:
#①合并后只取第一份数据的索引
In [14]: pd.concat([df1, df4], axis=1).reindex(df1.index)
Out[15]:
A B C D B D F
0 A0 B0 C0 D0 NaN NaN NaN
1 A1 B1 C1 D1 NaN NaN NaN
2 A2 B2 C2 D2 B2 D2 F2
3 A3 B3 C3 D3 B3 D3 F3
#②对第二份数据设置索引为第一份部分索引
In [16]: pd.concat([df1, df4.reindex(df1.index)], axis=1)
Out[17]:
A B C D B D F
0 A0 B0 C0 D0 NaN NaN NaN
1 A1 B1 C1 D1 NaN NaN NaN
2 A2 B2 C2 D2 B2 D2 F2
3 A3 B3 C3 D3 B3 D3 F3
内连接就是选取交集部分的索引或列名
In [18]: result = pd.concat([df1, df4], axis=1, join='inner')
内连接
很多时候需要合并的数据存在索引重叠的情况,对于很多没有实际意义的索引(比如单纯的默认索引0到n-1),我们可以设定忽略索引从而创建新的0到m-1的索引。
In [19]: result = pd.concat([df1, df4], ignore_index=True, sort=False)
忽略索引
Series与DataFrame合并时,会将Series转化为DataFrame的一列,该列名为Series的名称。
In [20]: s1 = pd.Series(['x0','x1','x2','x3'],name = 'x')
In [21]: result = pd.concat([df1,s1],axis=1)
混合数据合并 若Series未进行命名,则合并后的列名为连续的编号。
In [22]: s2 = pd.Series(['-0','-1','-2','-3'])
In [23]: result = pd.concat([df1,s2,s2,s2], axis=1)
Series未命令则连续编号 我们同样可以通过使用ignore_index = True删除并重新进行列名称编号。
In [24]: result = pd.concat([df1, s1], axis=1, ignore_index=True)
重置列名称
这样做的效率一般,使用append方法,可以将Series或字典数据添加到DataFrame。 Series数据追加到数据帧
In [25]: s2 = pd.Series(['X0', 'X1', 'X2', 'X3'], index=['A', 'B', 'C', 'D'])
In [26]: result = df1.append(s2, ignore_index=True)
行数据追加到数据帧 字典数据追加到数据帧
In [27]: dicts = [{'A': 1, 'B': 2, 'C': 3, 'X': 4},
...: {'A': 5, 'B': 6, 'C': 7, 'Y': 8}]
In [28]: result = df1.append(dicts, ignore_index=True, sort=False)
字典数据追加到数据帧
merge可根据一个或多个键(列)相关同DataFrame中的拼接起来。SQL或其他关系型数据库的用户对此应该会比较熟悉,因为它实现的就是数据库的join操作。
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:参与合并的左侧数据 right:参与合并的右侧数据 how:合并类型:inner(默认内连接)、outer(外连接)、left(左连接)、right(右连接) on:用于连接的列名,默认为左右侧数据共有的列名,指定时需要为左右侧数据都存在的列名 left_on:左侧数据用于连接的列 right_on:右侧数据用于连接的列 left_index:将左侧索引作为连接的列 right_index:将右侧索引作为连接的列 sort:排序,默认为True,设置为False可提高性能 suffixes:默认为('_x', '_y'),可以自定义如('date_x','date_y') copy:默认为True,如果是False,则不会复制不必要的可以提高效率 indicator:指示器,设置为True时会新增一列标识行数据存在于哪侧数据 validate:字符串,如果指定则会检测合并的数据是否满足指定类型
validate 类型说明: “one_to_one” or “1:1”: checks if merge keys are unique in both left and right datasets. “one_to_many” or “1:m”: checks if merge keys are unique in left dataset. “many_to_one” or “m:1”: checks if merge keys are unique in right dataset. “many_to_many” or “m:m”: allowed, but does not result in checks.
先看个简单的例子
In [29]: result = df1.append(dicts, ignore_index=True, sort=False)
In [30]: left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
...: 'A': ['A0', 'A1', 'A2', 'A3'],
...: 'B': ['B0', 'B1', 'B2', 'B3']})
...:
...: right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
...: 'C': ['C0', 'C1', 'C2', 'C3'],
...: 'D': ['D0', 'D1', 'D2', 'D3']})
In [31]: result = pd.merge(left, right, on='key')
在这里插入图片描述
left左连接 只保留左侧数据有的索引
In [32]: left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
...: 'key2': ['K0', 'K1', 'K0', 'K1'],
...: 'A': ['A0', 'A1', 'A2', 'A3'],
...: 'B': ['B0', 'B1', 'B2', 'B3']})
...:
...:
In [33]: right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
...: 'key2': ['K0', 'K0', 'K0', 'K0'],
...: 'C': ['C0', 'C1', 'C2', 'C3'],
...: 'D': ['D0', 'D1', 'D2', 'D3']})
In [34]: result = pd.merge(left, right, how='left', on=['key1', 'key2'])
left左连接 right右连接 只保留右侧数据有的索引
In [35]: result = pd.merge(left, right, how='right', on=['key1', 'key2'])
right右连接 outer外连接 外连接会保留左右两侧全部的索引
In [36]: result = pd.merge(left, right, how='outer', on=['key1', 'key2'])
outer外连接 inner内连接 外连接只保留左右两侧均有的索引,这个也是默认的连接形式
In [37]: result = pd.merge(left, right, how='inner', on=['key1', 'key2'])
inner内连接
validate参数可以指定一对一、一对多、多对一和多对多的情况,若不满足对应情况则在合并时会发生异常。
In [38]: left = pd.DataFrame({'A' : [1,2], 'B' : [1, 2]})
In [39]: right = pd.DataFrame({'A' : [4,5,6], 'B': [2, 2, 2]})
以上left和right有重复项,都包含A和B名称的列,默认情况下是会根据两个都有的列名进行合并,若设置validate='one_to_one'则会报错。
In [40]: result
Out[41]:
Empty DataFrame
Columns: [A, B]
Index: []
In [42]: result = pd.merge(left, right,on = 'B',how ='outer',validate='one_to_one')
"Merge keys are not unique in right dataset; "
MergeError: Merge keys are not unique in right dataset; not a one-to-one merge
若我们设置validate='one_to_many'则可正常合并。
In [43]: pd.merge(left, right, on='B', how='outer', validate="one_to_many")
Out[44]:
A_x B A_y
0 1 1 NaN
1 2 2 4.0
2 2 2 5.0
3 2 2 6.0
In [45]: pd.merge(left, right, on='B', how='outer', validate="many_to_many")
Out[46]:
A_x B A_y
0 1 1 NaN
1 2 2 4.0
2 2 2 5.0
3 2 2 6.0
默认情况下,indicator为False,若我们设置为True,则会在合并数据后新增一列标识
In [47]: df1 = pd.DataFrame({'col1': [0, 1], 'col_left': ['a', 'b']})
In [94]: df2 = pd.DataFrame({'col1': [1, 2, 2], 'col_right': [2, 2, 2]})
In [48]: df1
Out[49]:
col1 col_left
0 0 a
1 1 b
In [50]: df2
Out[51]:
col1 col_right
0 1 2
1 2 2
2 2 2
In [52]: pd.merge(df1, df2, on='col1', how='outer', indicator=True)
Out[53]:
col1 col_left col_right _merge
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only
我们也可以对indicator辅助列进行命名,通过传递参数形式。
In [54]: pd.merge(df1, df2, on='col1', how='outer', indicator='辅助标识器')
Out[55]:
col1 col_left col_right 辅助标识器
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only
当我们想合并的两个数据出现没有公共列名的情况,可以用left_on和right_on分别指定左右两侧数据用于匹配的列。
In [56]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
...: 'B': ['B0', 'B1', 'B2', 'B3'],
...: 'key': ['K0', 'K1', 'K0', 'K1']})
...:
...:
In [57]: right = pd.DataFrame({'C': ['C0', 'C1'],
...: 'D': ['D0', 'D1'],
...: 'key2': ['K0', 'K1']})
In [58]: result = pd.merge(left, right, left_on='key', right_on='key2',how='left', sort=False)
In [59]: result
Out[60]:
A B key C D key2
0 A0 B0 K0 C0 D0 K0
1 A1 B1 K1 C1 D1 K1
2 A2 B2 K0 C0 D0 K0
3 A3 B3 K1 C1 D1 K1
join可以将两个没用共同列名的数据进行快速合并,默认是保留被被合并的数据索引
In [61]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
...: 'B': ['B0', 'B1', 'B2']},
...: index=['K0', 'K1', 'K2'])
In [62]: right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
...: 'D': ['D0', 'D2', 'D3']},
...: index=['K0', 'K2', 'K3'])
In [63]: result = left.join(right)
join简单案例 join接受的参数有how、on和suffix等 以下两个表达式是等效的:
>>>left.join(right, on=key_or_keys)
>>>pd.merge(left, right, left_on=key_or_keys, right_index=True,
how='left', sort=False)
比如:
join
In [64]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
...: 'B': ['B0', 'B1', 'B2', 'B3'],
...: 'key': ['K0', 'K1', 'K0', 'K1']})
...:
...:
In [65]: right = pd.DataFrame({'C': ['C0', 'C1'],
...: 'D': ['D0', 'D1']},
...: index=['K0', 'K1'])
In [66]: result = left.join(right, on='key')
In [67]: result
Out[68]:
A B key C D
0 A0 B0 K0 C0 D0
1 A1 B1 K1 C1 D1
2 A2 B2 K0 C0 D0
3 A3 B3 K1 C1 D1
In [69]: result = pd.merge(left, right, left_on='key', right_index=True,how='left', sort=False)
In [70]: result
Out[71]:
A B key C D
0 A0 B0 K0 C0 D0
1 A1 B1 K1 C1 D1
2 A2 B2 K0 C0 D0
3 A3 B3 K1 C1 D1
参考资料 ①https://pandas.pydata.org/docs/user_guide/merging.html#timeseries-friendly-merging
嗨,你还在看吗?