一文搞定pandas的数据合并
在实际处理数据业务需求中,我们经常会遇到这样的需求:将多个表连接起来再进行数据的处理和分析,类似SQL中的连接查询功能。
pandas中也提供了几种方法来实现这个功能,表现最突出、使用最为广泛的方法是merge。本文中将下面👇四种方法及参数通过实际案例来进行具体讲解。
- merge
- append
- join
- concat
文章目录
导入库
做数据分析的时候这两个库是必须导入的,国际惯例一般。
1 | import pandas as pd |
merge
官方参数
官方提供的merge
函数的参数如下:
下面将通过案例讲解几个重要参数的使用方法:
1 | DataFrame.merge(left, right, |
模拟数据
注意4组数据的不同
1 | # 生成3个DataFrame型的数据 |
key | data1 | |
---|---|---|
0 | a | 0 |
1 | b | 1 |
2 | b | 2 |
1 | df2 = pd.DataFrame({'key':['a','b','c'], # a---b---c |
key | data2 | |
---|---|---|
0 | a | 3 |
1 | b | 4 |
2 | c | 5 |
1 | df3 = pd.DataFrame({'key':['b','c','d'], # b---c---d |
key | data3 | |
---|---|---|
0 | b | 6 |
1 | c | 7 |
2 | d | 8 |
1 | df4 = pd.DataFrame({'key':['a','b','c'], # a---b---c |
key | data4 | |
---|---|---|
0 | a | 9 |
1 | b | 10 |
2 | c | 11 |
使用默认参数
1 | # 合并df1和df2 |
key | data1 | data2 | |
---|---|---|---|
0 | a | 0 | 3 |
1 | b | 1 | 4 |
2 | b | 2 | 4 |
1 | # 效果同上 |
key | data1 | data2 | |
---|---|---|---|
0 | a | 0 | 3 |
1 | b | 1 | 4 |
2 | b | 2 | 4 |
参数how
how
参数的取值有4种:
- inner(默认)
- outer
- right
- left
1 | # 1-默认使用inner:通过key的交集取值 |
key | data1 | data2 | |
---|---|---|---|
0 | a | 0 | 3 |
1 | b | 1 | 4 |
2 | b | 2 | 4 |
1 | pd.merge(df1,df2,how='inner') |
key | data1 | data2 | |
---|---|---|---|
0 | a | 0 | 3 |
1 | b | 1 | 4 |
2 | b | 2 | 4 |
1 | # 2-outer: 保留两个数据框的全部数据,不存在的则用NaN |
key | data1 | data2 | |
---|---|---|---|
0 | a | 0.0 | 3 |
1 | b | 1.0 | 4 |
2 | b | 2.0 | 4 |
3 | c | NaN | 5 |
1 | df1 |
key | data1 | |
---|---|---|
0 | a | 0 |
1 | b | 1 |
2 | b | 2 |
1 | df2 |
key | data2 | |
---|---|---|
0 | a | 3 |
1 | b | 4 |
2 | c | 5 |
1 | # 3- left: 保留左边的全部数据 |
key | data1 | data3 | |
---|---|---|---|
0 | a | 0 | NaN |
1 | b | 1 | 6.0 |
2 | b | 2 | 6.0 |
1 | # 左表df1 |
key | data1 | |
---|---|---|
0 | a | 0 |
1 | b | 1 |
2 | b | 2 |
1 | df3 |
key | data3 | |
---|---|---|
0 | b | 6 |
1 | c | 7 |
2 | d | 8 |
1 | # 4-right:保留右表的全部数据 |
key | data1 | data3 | |
---|---|---|---|
0 | b | 1.0 | 6 |
1 | b | 2.0 | 6 |
2 | c | NaN | 7 |
3 | d | NaN | 8 |
1 | # 右表df3 |
key | data3 | |
---|---|---|
0 | b | 6 |
1 | c | 7 |
2 | d | 8 |
1 | df1 |
key | data1 | |
---|---|---|
0 | a | 0 |
1 | b | 1 |
2 | b | 2 |
参数on
用于连接的列索引列名,必须同时存在于左右的两个dataframe型数据中,类似SQL中两个表的相同字段属性
如果没有指定或者其他参数也没有指定,则以两个dataframe型数据的相同键作为连接键
on参数为单个字段
1 | # pd.merge(df1,df2) |
key | data1 | data2 | |
---|---|---|---|
0 | a | 0 | 3 |
1 | b | 1 | 4 |
2 | b | 2 | 4 |
1 | df1 |
key | data1 | |
---|---|---|
0 | a | 0 |
1 | b | 1 |
2 | b | 2 |
1 | df2 |
key | data2 | |
---|---|---|
0 | a | 3 |
1 | b | 4 |
2 | c | 5 |
1 | # 另一个例子 |
key | A | B | |
---|---|---|---|
0 | K0 | A0 | B0 |
1 | K1 | A1 | B1 |
2 | K2 | A2 | B2 |
3 | K3 | A3 | B3 |
1 | right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'], |
key | C | D | |
---|---|---|---|
0 | K0 | C0 | D0 |
1 | K1 | C1 | D1 |
2 | K2 | C2 | D2 |
3 | K3 | C3 | D3 |
1 | # on参数传递的key作为连接键-类似SQL中两个表的关联字段 |
key | A | B | C | D | |
---|---|---|---|---|---|
0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | A1 | B1 | C1 | D1 |
2 | K2 | A2 | B2 | C2 | D2 |
3 | K3 | A3 | B3 | C3 | D3 |
on参数为多个字段-列表形式
1 | left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'], |
key1 | key2 | A | B | |
---|---|---|---|---|
0 | K0 | K0 | A0 | B0 |
1 | K0 | K1 | A1 | B1 |
2 | K1 | K0 | A2 | B2 |
3 | K2 | K1 | A3 | B3 |
1 | right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'], |
key1 | key2 | C | D | |
---|---|---|---|---|
0 | K0 | K0 | C0 | D0 |
1 | K1 | K0 | C1 | D1 |
2 | K1 | K0 | C2 | D2 |
3 | K2 | K0 | C3 | D3 |
1 | # on参数为列表形式 |
key1 | key2 | A | B | C | D | |
---|---|---|---|---|---|---|
0 | K0 | K0 | A0 | B0 | C0 | D0 |
1 | K1 | K0 | A2 | B2 | C1 | D1 |
2 | K1 | K0 | A2 | B2 | C2 | D2 |
参数left_on/right_on
1 | df7 = pd.DataFrame({'l_key':['b','c','d'], |
l_key | data7 | |
---|---|---|
0 | b | 6 |
1 | c | 7 |
2 | d | 8 |
1 | df8 = pd.DataFrame({'r_key':['b','c','d'], # 某两个键的名字不同,但是取值相同 |
r_key | data8 | |
---|---|---|
0 | b | 9 |
1 | c | 10 |
2 | d | 11 |
1 | pd.merge(df7,df8,left_on='l_key',right_on='r_key') |
l_key | data7 | r_key | data8 | |
---|---|---|---|---|
0 | b | 6 | b | 9 |
1 | c | 7 | c | 10 |
2 | d | 8 | d | 11 |
参数suffixes
合并的时候一列两个表同名,但是取值不同,如果都想要保存下来,就使用加后缀的方法,默认是_x,_y
1 | df9 = pd.DataFrame({'key':['b','c','d'], |
key | data | |
---|---|---|
0 | b | 5 |
1 | c | 6 |
2 | d | 7 |
1 | df10 = pd.DataFrame({'key':['b','c','d'], |
key | data | |
---|---|---|
0 | b | 9 |
1 | c | 5 |
2 | d | 10 |
1 | pd.merge(df9,df10,on='key',suffixes=['_left','_right']) # 自定义后缀 |
key | data_left | data_right | |
---|---|---|---|
0 | b | 5 | 9 |
1 | c | 6 | 5 |
2 | d | 7 | 10 |
1 | pd.merge(df9,df10,on='key',suffixes=['_x','_y']) # 官方默认后缀_x,_y |
key | data_x | data_y | |
---|---|---|---|
0 | b | 5 | 9 |
1 | c | 6 | 5 |
2 | d | 7 | 10 |
参数sort
对连接的时候相同键的取值进行排序
1 | df9 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], |
A | B | key | |
---|---|---|---|
0 | A0 | B0 | K0 |
1 | A1 | B1 | K1 |
2 | A2 | B2 | K0 |
3 | A3 | B3 | K1 |
1 | df10 = pd.DataFrame({'C': ['C0', 'C1'], |
C | D | |
---|---|---|
K0 | C0 | D0 |
K1 | C1 | D1 |
1 | pd.merge(df9, df10, left_on='key', right_index=True, how='left', sort=False) |
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 |
1 | # 对连接的键(key)的取值进行排序 |
A | B | key | C | D | |
---|---|---|---|---|---|
0 | A0 | B0 | K0 | C0 | D0 |
2 | A2 | B2 | K0 | C0 | D0 |
1 | A1 | B1 | K1 | C1 | D1 |
3 | A3 | B3 | K1 | C1 | D1 |
concat
官方参数
concat方法是将两个DataFrame数据框中的数据进行合并
- 通过axis参数指定是在行还是列方向上合并
- 参数
ignore_index
实现合并后的索引重排
生成数据
1 | data1 = pd.DataFrame({'key1': ['math','chinese','english'], 'value': [87,92,83]}) |
key1 | value | |
---|---|---|
0 | math | 87 |
1 | chinese | 92 |
2 | english | 83 |
1 | data2 = pd.DataFrame({'key1': ['math','chinese','english'], 'value': [97,82,76]}) |
key1 | value | |
---|---|---|
0 | math | 97 |
1 | chinese | 82 |
2 | english | 76 |
指定合并轴
1 | pd.concat([data1, data2]) # 合并方向默认是axis=0,行方向上合并 |
key1 | value | |
---|---|---|
0 | math | 87 |
1 | chinese | 92 |
2 | english | 83 |
0 | math | 97 |
1 | chinese | 82 |
2 | english | 76 |
1 | pd.concat([data1, data2],axis=1) # 改成axis=1,列方向上合并 |
key1 | value | key1 | value | |
---|---|---|---|---|
0 | math | 87 | math | 97 |
1 | chinese | 92 | chinese | 82 |
2 | english | 83 | english | 76 |
改变索引
1 | pd.concat([data1, data2], ignore_index=True) |
key1 | value | |
---|---|---|
0 | math | 87 |
1 | chinese | 92 |
2 | english | 83 |
3 | math | 97 |
4 | chinese | 82 |
5 | english | 76 |
1 | pd.concat([data1, data2]) |
key1 | value | |
---|---|---|
0 | math | 87 |
1 | chinese | 92 |
2 | english | 83 |
0 | math | 97 |
1 | chinese | 82 |
2 | english | 76 |
join参数
1 | data3 = pd.DataFrame({'key3': ['math','chinese','english'], |
key3 | value | |
---|---|---|
0 | math | 95 |
1 | chinese | 88 |
2 | english | 89 |
1 | data4 = pd.DataFrame({'key4': ['math','chinese','english'], |
key4 | value | |
---|---|---|
0 | math | 90 |
1 | chinese | 83 |
2 | english | 94 |
1 | pd.concat([data3, data4]) |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
0 | NaN | math | 90 |
1 | NaN | chinese | 83 |
2 | NaN | english | 94 |
1 | pd.concat([data3, data4], join='outer') # 字段如果不存在,则用NaN代 |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
0 | NaN | math | 90 |
1 | NaN | chinese | 83 |
2 | NaN | english | 94 |
1 | pd.concat([data3, data4], join='inner') # 只合并相同的字段属性 |
value | |
---|---|
0 | 95 |
1 | 88 |
2 | 89 |
0 | 90 |
1 | 83 |
2 | 94 |
sort-属性排序
1 | pd.concat([data3, data4], sort=False) |
key3 | value | key4 | |
---|---|---|---|
0 | math | 95 | NaN |
1 | chinese | 88 | NaN |
2 | english | 89 | NaN |
0 | NaN | 90 | math |
1 | NaN | 83 | chinese |
2 | NaN | 94 | english |
1 | # 默认排序 |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
0 | NaN | math | 90 |
1 | NaN | chinese | 83 |
2 | NaN | english | 94 |
append
官方参数
基本使用
1 | data3.append(data4) # 等同下面的语句中concat写法 |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
0 | NaN | math | 90 |
1 | NaN | chinese | 83 |
2 | NaN | english | 94 |
1 | pd.concat([data3, data4]) |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
0 | NaN | math | 90 |
1 | NaN | chinese | 83 |
2 | NaN | english | 94 |
改变索引-自然数排序
1 | data3.append(data4, ignore_index=True) # 设置参数 |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
3 | NaN | math | 90 |
4 | NaN | chinese | 83 |
5 | NaN | english | 94 |
1 | data3.append(data4) |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
0 | NaN | math | 90 |
1 | NaN | chinese | 83 |
2 | NaN | english | 94 |
sort=True-属性的排序
1 | data3.append(data4) # 默认对字段属性排序 |
key3 | key4 | value | |
---|---|---|---|
0 | math | NaN | 95 |
1 | chinese | NaN | 88 |
2 | english | NaN | 89 |
0 | NaN | math | 90 |
1 | NaN | chinese | 83 |
2 | NaN | english | 94 |
1 | data3.append(data4, sort=False) |
key3 | value | key4 | |
---|---|---|---|
0 | math | 95 | NaN |
1 | chinese | 88 | NaN |
2 | english | 89 | NaN |
0 | NaN | 90 | math |
1 | NaN | 83 | chinese |
2 | NaN | 94 | english |
1 |
join
官方参数
通过相同索引合并
1 | data5 = pd.DataFrame({'A': [81,97,88],'B': [93,88,78]}, |
A | B | |
---|---|---|
K0 | 81 | 93 |
K1 | 97 | 88 |
K2 | 88 | 78 |
1 | data6 = pd.DataFrame({'C': [95,77,80],'D': [80,98,84]}, |
C | D | |
---|---|---|
K0 | 95 | 80 |
K1 | 77 | 98 |
K2 | 80 | 84 |
1 | data5.join(data6) # 同下效果 |
A | B | C | D | |
---|---|---|---|---|
K0 | 81 | 93 | 95 | 80 |
K1 | 97 | 88 | 77 | 98 |
K2 | 88 | 78 | 80 | 84 |
1 | pd.concat([data5, data6],axis=1) # 指定沿着axis=1 |
A | B | C | D | |
---|---|---|---|---|
K0 | 81 | 93 | 95 | 80 |
K1 | 97 | 88 | 77 | 98 |
K2 | 88 | 78 | 80 | 84 |
1 | data7 = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'], |
key | A | |
---|---|---|
0 | K0 | A0 |
1 | K1 | A1 |
2 | K2 | A2 |
3 | K3 | A3 |
4 | K4 | A4 |
5 | K5 | A5 |
1 | data8 = pd.DataFrame({'key': ['K0', 'K1', 'K2'], |
key | B | |
---|---|---|
0 | K0 | B0 |
1 | K1 | B1 |
2 | K2 | B2 |
相同字段属性指后缀
1 | data7.join(data8,lsuffix='_left', rsuffix='_right') # 存在相同的字段,指定新生成的字段后缀 |
key_left | A | key_right | B | |
---|---|---|---|---|
0 | K0 | A0 | K0 | B0 |
1 | K1 | A1 | K1 | B1 |
2 | K2 | A2 | K2 | B2 |
3 | K3 | A3 | NaN | NaN |
4 | K4 | A4 | NaN | NaN |
5 | K5 | A5 | NaN | NaN |
相同字段变成索引index
1 | data7.set_index('key').join(data8.set_index('key')) |
A | B | |
---|---|---|
key | ||
K0 | A0 | B0 |
K1 | A1 | B1 |
K2 | A2 | B2 |
K3 | A3 | NaN |
K4 | A4 | NaN |
K5 | A5 | NaN |
相同字段保留一次
1 | data7.join(data8.set_index('key'), on='key') |
key | A | B | |
---|---|---|---|
0 | K0 | A0 | B0 |
1 | K1 | A1 | B1 |
2 | K2 | A2 | B2 |
3 | K3 | A3 | NaN |
4 | K4 | A4 | NaN |
5 | K5 | A5 | NaN |
1 | data7.join(data8.set_index('key'), on='key').set_index('key') # 和上一种方法的转换效果相同,最后在使用一次set_index() |
A | B | |
---|---|---|
key | ||
K0 | A0 | B0 |
K1 | A1 | B1 |
K2 | A2 | B2 |
K3 | A3 | NaN |
K4 | A4 | NaN |
K5 | A5 | NaN |