简介
pandas提供了一套合并数据集操作的方法:
- pandas.merge()可根据一个或者多个键将不同的DataFrame连接在一起,类似于SQL数据库中的合并操作;
- pandas.concat()可以沿某个轴将多个数据集连接在一起。
接下来将分别对这两种方法进行介绍。
merge()函数
merge()
函数中的参数如下:
参数 | 描述 |
---|---|
left | 参与合并到左侧DataFrame |
right | 参与合并到右侧DataFrame |
how | 合并方式(‘inner’、‘outer’、‘left’、‘right’)其中之一,默认为‘inner’ |
on | 用于连接的列名。未指定则使用两列的交集作为连接键 |
left_on | 左侧DataFrame中用作连接键的列 |
right_on | 右侧DataFrame中用作连接键的列 |
left_index | 将左侧的行索引用作连接键 |
right_index | 将右侧的行索引用作连接键 |
sort | 对合并后的数据进行排序,默认为True |
suffixes | 用于追加到重叠列名的末尾。例如,左右两个DataFrame都有‘data’列,则结果中就会出现‘data_x’和‘data_y’ |
copy | 默认总是复制 |
以一个例子开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
>>>import numpy as np >>>import pandas as pd >>>df1 = pd.DataFrame({'data1': np.arange(7), 'name': list('bbbaacd')}) >>>df1 data1 name 0 0 b 1 1 b 2 2 b 3 3 a 4 4 a 5 5 c 6 6 d >>>df2 = pd.DataFrame({'data2': [0, 2, 4], 'name': ['a', 'b', 'c']}) >>>df2 data2 name 0 0 a 1 2 b 2 4 c >>>pd.merge(df1, df2) data1 name data2 0 0 b 2 1 1 b 2 2 2 b 2 3 3 a 0 4 4 a 0 5 5 c 4 |
在这个例子中,默认使用两个DataFrame的交集作为合并键,也就是'name'
列。这是多对一的合并,也就是说df1中有多个重复值与df2中一个值合并(2个’a’对一个’a’,3个’b’对一个’b’)。默认是'inner'
的方式,只要两者都有的值才合并(’a’, ‘b’, ‘c’),还可以使用其他的合并方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 并集合并 >>>pd.merge(df1, df2, how='outer') data1 name data2 0 0 b 2.0 1 1 b 2.0 2 2 b 2.0 3 3 a 0.0 4 4 a 0.0 5 5 c 4.0 6 6 d NaN # 左合并 >>>pd.merge(df1, df2, how='left') data1 name data2 0 0 b 2.0 1 1 b 2.0 2 2 b 2.0 3 3 a 0.0 4 4 a 0.0 5 5 c 4.0 6 6 d NaN # 右合并 >>>pd.merge(df1, df2, how='right') data1 name data2 0 0 b 2 1 1 b 2 2 2 b 2 3 3 a 0 4 4 a 0 5 5 c 4 |
可以根据想要的合并方式选择参数;如何合并的列名不一样,此时就要通过指定列名进行合并:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
>>>df1 = pd.DataFrame({'data1': np.arange(7), 'name1': list('bbbaacd')}) >>>df1 data1 name1 0 0 b 1 1 b 2 2 b 3 3 a 4 4 a 5 5 c 6 6 d >>>df2 = pd.DataFrame({'data2': [0, 2, 4], 'name2': ['a', 'b', 'c']}) >>>df2 data2 name2 0 0 a 1 2 b 2 4 c >>>pd.merge(df1, df2, left_on='name1', right_on='name2') data1 name1 data2 name2 0 0 b 2 b 1 1 b 2 b 2 2 b 2 b 3 3 a 0 a 4 4 a 0 a 5 5 c 4 c |
可以看出,默认也是交集合并,通过left_on
和right_on
指定了需要合并的列,得到合并后的结果。除了多对一的合并,还有多对多的合并,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
>>>df1 = pd.DataFrame({'data1': np.arange(7), 'name': list('bbbaacd')}) >>>df1 data1 name 0 0 b 1 1 b 2 2 b 3 3 a 4 4 a 5 5 c 6 6 d >>>df2 = pd.DataFrame({'data2': np.arange(4), 'name': list('aabc')}) >>>df2 data2 name 0 0 a 1 1 a 2 2 b 3 3 c >>>pd.merge(df1, df2, on='name', how='outer') data1 name data2 0 0 b 2.0 1 1 b 2.0 2 2 b 2.0 3 3 a 0.0 4 3 a 1.0 5 4 a 0.0 6 4 a 1.0 7 5 c 3.0 8 6 d NaN |
多对多合并的原则是:df1中有两个’a’行,df2中有两个’a’行,因此总共就有四个’a’行,是两者数量相乘。还可以根据多个列进行合并:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
>>>df1 = pd.DataFrame({'data1': range(3), 'name1': list('aab'), 'name2': ['one', 'one', 'two']}) >>>df1 data1 name1 name2 0 0 a one 1 1 a one 2 2 b two >>>df2 = pd.DataFrame({'data2': range(3), 'name1': list('aab'), 'name2': ['one', 'two', 'one']}) >>>df2 data2 name1 name2 0 0 a one 1 1 a two 2 2 b one >>>pd.merge(df1, df2, on=['name1', 'name2'], how='outer') data1 name1 name2 data2 0 0.0 a one 0.0 1 1.0 a one 0.0 2 2.0 b two NaN 3 NaN a two 1.0 4 NaN b one 2.0 |
在这里两个键形成一个组合,df1中有两个(a, one)
,而df2中只有一个(a, one)
,因此相乘就是两个。
merge()
函数使用起来是十分灵活的,不仅可以根据列合并,而且还能将索引-索引合并,索引-列合并,只需要指定相应的参数即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
>>>df1 data1 name1 name2 0 0 a one 1 1 a one 2 2 b two >>>df2 data2 name1 name2 0 0 a one 1 1 a two 2 2 b one # 索引-索引合并 >>>pd.merge(df1, df2, left_index=True, right_index=True) data1 name1_x name2_x data2 name1_y name2_y 0 0 a one 0 a one 1 1 a one 1 a two 2 2 b two 2 b one >>>df3 = pd.DataFrame({'data3': range(3)}, index=list('abc')) >>>df3 data3 a 0 b 1 c 2 >>>pd.merge(df1, df3, left_on='name1', right_index=True, how='outer') data1 name1 name2 data3 0 0.0 a one 0 1 1.0 a one 0 2 2.0 b two 1 2 NaN c NaN 2 |
参见最开始的merge()
函数的参数设定,通过调控参数能够实现非常灵活的合并操作。
concat()函数
该函数能够实现轴向数据集的连接,同样它的参数有:
参数 | 描述 |
---|---|
objs | 参与连接的对象,必需参数 |
axis | 指定轴,默认为0 |
join | ‘inner’或者‘outer’,默认为‘outer’,指明其他轴的索引按哪种方式进行合并 |
join_axes | 指明用于其他n-1条轴的索引,不执行并集/交集运算 |
keys | 与连接对象有关的值,用于形成连接轴向上的层次化索引。可以是任意值的列表或数组 |
levels | 指定用作层次化索引各级别上的索引 |
names | 用于创建分层级别的名称,如果设置了keys和levels |
verify_integrity | 检查结果对象新轴上的重复情况,如果发现则引发异常。默认False允许重复 |
ignore_index | 不保留连接轴上的索引,产生一组新索引 |
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
>>>a1 = pd.Series([0, 1]) >>>a2 = pd.Series([2, 3, 4]) >>>a3 = pd.Series([5, 6]) >>>a = pd.concat([a1, a2, a3]) >>>a 0 0 1 1 0 2 1 3 2 4 0 5 1 6 dtype: int64 >>>pd.concat([a1, a2, a3], ignore_index=True) 0 0 1 1 2 2 3 3 4 4 5 5 6 6 dtype: int64 # 或者 >>>a.set_axis(range(7), inplace=True) >>>a 0 0 1 1 2 2 3 3 4 4 5 5 6 6 dtype: int64 |
将三个Series的值和索引连接起来,使用ignore_index=True
能够忽略索引值,或者使用set_axis
函数可以重新修改索引。
默认是在axis=0
上连接,我们也可以指定方向:
1 2 3 4 5 |
>>>pd.concat([a1, a2, a3], axis=1) 0 1 2 0 0.0 2 5.0 1 1.0 3 6.0 2 NaN 4 NaN |
此时是在索引的并集上进行连接,可以使用join
参数改变连接方式:
1 2 3 4 |
>>>pd.concat([a1, a2, a3], axis=1, join='inner') 0 1 2 0 0 2 5 1 1 3 6 |
可以通过join_axes
指定在其他轴上使用的索引:
1 2 3 4 5 |
>>>pd.concat([a1, a3], axis=1, join_axes=[[0, 2, 1]]) 0 1 0 0.0 5.0 2 NaN NaN 1 1.0 6.0 |
可以通过keys
参数创建一个层次化索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>>>pd.concat([a1, a2, a3], keys=['one' , 'two', 'three']) one 0 0 1 1 two 0 2 1 3 2 4 three 0 5 1 6 dtype: int64 >>>pd.concat([a1, a2, a3], axis=1, keys=['one', 'two', 'three']) one two three 0 0.0 2 5.0 1 1.0 3 6.0 2 NaN 4 NaN |
对DataFrame的操作也是一样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
>>>df1 data1 name1 name2 0 0 a one 1 1 a one 2 2 b two >>>df2 data2 name1 name2 0 0 a one 1 1 a two 2 2 b one >>>pd.concat([df1, df2], axis=1, keys=['one', 'two']) one two data1 name1 name2 data2 name1 name2 0 0 a one 0 a one 1 1 a one 1 a two 2 2 b two 2 b one # 或者 >>>pd.concat({'one': df1, 'two': df2}, axis=1) one two data1 name1 name2 data2 name1 name2 0 0 a one 0 a one 1 1 a one 1 a two 2 2 b two 2 b one |
可以看出在DataFrame上有两种方法构建层次化索引,要么使用keys
参数,要么构建一个字典,字典的键会作为keys
的值。
使用names
参数可以管理层次化索引:
1 2 3 4 5 6 |
>>>pd.concat([df1, df2], axis=1, keys=['one', 'two'], names=['fist_layer', 'second_layer']) fist_layer one two second_layer data1 name1 name2 data2 name1 name2 0 0 a one 0 a one 1 1 a one 1 a two 2 2 b two 2 b one |
总结
pandas提供的合并操作非常简单和实用,功能都是从实际需求中出发, 让我们能够更加高效地处理数据。