Merge, Join, Concat
大家好,我有回来啦,这周更新的有点慢,主要是因为我更新了个人简历哈哈,如果感兴趣的朋友可以去看看哈:
我的主页
个人认为还是很漂亮的~,不得不说,很多时候老外的设计能力还是很强。
好了,有点扯远了,这一期我想和大家分享的是 pandas 中最常见的几种方法,这些方法如果你学会了,某种程度上可以很好的替代 Excel,这篇文章是 pandas 之旅的第三篇,主要会从以下几个方面和大家分享我的心得体会:
Merge
Join
Concat
源码及 GitHub 地址
话不多说,让我们开始今天的 Pandas 之旅吧!
1. Merge
首先 merge 的操作非常类似 sql 里面的 join,实现将两个 Dataframe 根据一些共有的列连接起来,当然,在实际场景中,这些共有列一般是 Id,连接方式也丰富多样,可以选择 inner(默认),left,right,outer 这几种模式,分别对应的是内连接,左连接,右连接
1.1 InnerMerge (内连接)
首先让我们简单的创建两个 DF, 分别为 DataFrame1,DataFrame2, 他们的公有列是 key
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
# Let’s make a dframe
dframe1 = DataFrame({‘key’:[‘X’,’Z’,’Y’,’Z’,’X’,’X’],’value_df1′: np.arange(6)})
dframe1
key
value_df1
0
X
0
1
Z
1
2
Y
2
3
Z
3
4
X
4
5
X
5
#Now lets make another dframe
dframe2 = DataFrame({‘key’:[‘Q’,’Y’,’Z’],’value_df2′:[1,2,3]})
dframe2
key
value_df2
0
Q
1
1
Y
2
2
Z
3
我们现在可以简单地使用 pd.merge(dframe1,dframe2) 来实现 Merge 功能
pd.merge(dframe1,dframe2)
key
value_df1
value_df2
0
Z
1
3
1
Z
3
3
2
Y
2
2
我们现在需要注意一点,X 仅仅是存在于 dframe1 的 key,在 dframe2 中不存在,因此大家可以发现,当我们调用 pd.merge 的时候,会自动默认为 inner join,我们再换一种方式写一下,大家就明白了:
pd.merge(dframe1,dframe2,on=’key’,how=’inner’)
key
value_df1
value_df2
0
Z
1
3
1
Z
3
3
2
Y
2
2
大家可以发现结果是一样的,看到这里,对 sql 熟悉的朋友们已经有感觉了估计,因为实在是太像了,如果我们不通过 on 和 how 来指定
想要 merge 的公有列或者方式,那么 pd.merge 就会自动寻找到两个 DataFrame 的相同列并自动默认为 inner join,至此,
估计大家也可以猜出其他几种模式的 merge 啦
1.2 LeftMerge (左连接)
现在同样的,让我们看一下 how=’left’ 的情况,这是一个左连接
pd.merge(dframe1,dframe2,on=’key’,how=’left’)
key
value_df1
value_df2
0
X
0
NaN
1
Z
1
3.0
2
Y
2
2.0
3
Z
3
3.0
4
X
4
NaN
5
X
5
NaN
我们可以看到返回的是 dframe1 的所有 key 值对应的结果,如果在 dframe2 中不存在,显示为 Nan 空值
1.3 RightMerge (右连接)
右连接的原理和左连接正相反
pd.merge(dframe1,dframe2,on=’key’,how=’right’)
key
value_df1
value_df2
0
Z
1.0
3
1
Z
3.0
3
2
Y
2.0
2
3
Q
NaN
1
这里 Q 只存在于 drame2 的 key 中
1.4 OuterMerge (全连接)
#Choosing the “outer” method selects the union of both keys
pd.merge(dframe1,dframe2,on=’key’,how=’outer’)
key
value_df1
value_df2
0
X
0.0
NaN
1
X
4.0
NaN
2
X
5.0
NaN
3
Z
1.0
3.0
4
Z
3.0
3.0
5
Y
2.0
2.0
6
Q
NaN
1.0
这里就是一个并集的形式啦,其实就是一个 union 的结果,会把 key 这一列在两个 Dataframe 出现的所有值全部显示出来,如果有空值显示为 Nan
1.5 MultipleKey Merge (基于多个 key 上的 merge)
刚才我们都是仅仅实现的在一个 key 上的 merge,当然我们也可以实现基于多个 keys 的 merge
# Dframe on left
df_left = DataFrame({‘key1’: [‘SF’, ‘SF’, ‘LA’],
‘key2’: [‘one’, ‘two’, ‘one’],
‘left_data’: [10,20,30]})
df_left
key1
key2
left_data
0
SF
one
10
1
SF
two
20
2
LA
one
30
#Dframe on right
df_right = DataFrame({‘key1’: [‘SF’, ‘SF’, ‘LA’, ‘LA’],
‘key2’: [‘one’, ‘one’, ‘one’, ‘two’],
‘right_data’: [40,50,60,70]})
df_right
key1
key2
right_data
0
SF
one
40
1
SF
one
50
2
LA
one
60
3
LA
two
70
这是内连接(交集)的结果
#Merge,Inner
pd.merge(df_left, df_right, on=[‘key1’, ‘key2’])
key1
key2
left_data
right_data
0
SF
one
10
40
1
SF
one
10
50
2
LA
one
30
60
这是外连接(并集)的结果
#Merge,Outer
pd.merge(df_left, df_right, on=[‘key1’, ‘key2′],how=’outer’)
key1
key2
left_data
right_data
0
SF
one
10.0
40.0
1
SF
one
10.0
50.0
2
SF
two
20.0
NaN
3
LA
one
30.0
60.0
4
LA
two
NaN
70.0
这里还有一个地方非常有意思,大家可以发现现在 df_left,df_right 作为 key 的两列分别是 key1 和 key2,它们的名字是相同的,刚刚我们是通过制定 on=[‘key1’, ‘key2′], 那如果我们只指定一列会怎么样呢?
pd.merge(df_left,df_right,on=’key1′)
key1
key2_x
left_data
key2_y
right_data
0
SF
one
10
one
40
1
SF
one
10
one
50
2
SF
two
20
one
40
3
SF
two
20
one
50
4
LA
one
30
one
60
5
LA
one
30
two
70
大家可以看到 pandas 自动把 key2 这一列拆分成了 key2_x 和 key2_y,都会显示在最后的 merge 结果里,如果我们想要给这两列重新命名,也是很容易的:
# We can also specify what the suffix becomes
pd.merge(df_left,df_right, on=’key1’,suffixes=(‘_lefty’,’_righty’))
key1
key2_lefty
left_data
key2_righty
right_data
0
SF
one
10
one
40
1
SF
one
10
one
50
2
SF
two
20
one
40
3
SF
two
20
one
50
4
LA
one
30
one
60
5
LA
one
30
two
70
像这样,我们可以通过 suffixes 参数来指定拆分的列的名字。
1.6 Merge on Index (基于 index 上的 merge)
我们还可以实现几个 Dataframe 基于 Index 的 merge,还是老样子,先让我们创建两个 Dataframe
df_left = DataFrame({‘key’: [‘X’,’Y’,’Z’,’X’,’Y’],
‘data’: range(5)})
df_right = DataFrame({‘group_data’: [10, 20]}, index=[‘X’, ‘Y’])
df_left
key
data
0
X
0
1
Y
1
2
Z
2
3
X
3
4
Y
4
df_right
group_data
X
10
Y
20
好了,现在我们想要实现两个 Dataframe 的 merge,但是条件是通过 df_left 的 Key 和 df_right 的 Index
pd.merge(df_left,df_right,left_on=’key’,right_index=True)
key
data
group_data
0
X
0
10
3
X
3
10
1
Y
1
20
4
Y
4
20
这样我们也可以得到结果。
# We can also get a union by using outer
pd.merge(df_left,df_right,left_on=’key’,right_index=True,how=’outer’)
key
data
group_data
0
X
0
10.0
3
X
3
10.0
1
Y
1
20.0
4
Y
4
20.0
2
Z
2
NaN
其他的 merge 方式就类似啦,这里就不一一说了,只是举一个 outer join 的例子
# 通过 outer 实现外连接,union 并集
pd.merge(df_left,df_right,left_on=’key’,right_index=True,how=’outer’)
key
data
group_data
0
X
0
10.0
3
X
3
10.0
1
Y
1
20.0
4
Y
4
20.0
2
Z
2
NaN
我们也可以尝试一些有意思的 merge,比如,如果一个 dataframe 的 index 是多层嵌套的情况:
df_left_hr = DataFrame({‘key1’: [‘SF’,’SF’,’SF’,’LA’,’LA’],
‘key2’: [10, 20, 30, 20, 30],
‘data_set’: np.arange(5.)})
df_right_hr = DataFrame(np.arange(10).reshape((5, 2)),
index=[[‘LA’,’LA’,’SF’,’SF’,’SF’],
[20, 10, 10, 10, 20]],
columns=[‘col_1’, ‘col_2’])
df_left_hr
key1
key2
data_set
0
SF
10
0.0
1
SF
20
1.0
2
SF
30
2.0
3
LA
20
3.0
4
LA
30
4.0
df_right_hr
col_1
col_2
LA
20
0
1
10
2
3
SF
10
4
5
10
6
7
20
8
9
现在我们穿建了两个 Dataframe 分别是 df_left_hr 和 df_right_hr(Index 两层),如果我们想通过使用 df_left_hr 的 key1,key2 及 df_right_hr 的 Index 作为 merge 的列,也是没有问题的
# Now we can merge the left by using keys and the right by its index
pd.merge(df_left_hr,df_right_hr,left_on=[‘key1′,’key2’],right_index=True)
key1
key2
data_set
col_1
col_2
0
SF
10
0.0
4
5
0
SF
10
0.0
6
7
1
SF
20
1.0
8
9
3
LA
20
3.0
0
1
基本到这里,我已经和大家分享了基础的 Merge 有关的所有操作,如果你平时生活工作中经常使用 Excel 执行类似操作的话,可以学习一下 Merge 哈,它会大幅度减轻你的工作强度的!
2.Join
现在我们可以接着来看 join 相关的操作,先让我们看一个小例子
left = pd.DataFrame({‘A’: [‘A0’, ‘A1’, ‘A2’, ‘A3’],
‘B’: [‘B0’, ‘B1’, ‘B2’, ‘B3’]},
index = [‘K0’, ‘K1’, ‘K2’, ‘K3’])
right = pd.DataFrame({‘C’: [‘C0’, ‘C1’, ‘C2’, ‘C3’],
‘D’: [‘D0’, ‘D1’, ‘D2’, ‘D3’]},
index = [‘K0’, ‘K1’, ‘K2’, ‘K3’])
left
A
B
K0
A0
B0
K1
A1
B1
K2
A2
B2
K3
A3
B3
right
C
D
K0
C0
D0
K1
C1
D1
K2
C2
D2
K3
C3
D3
left.join(right)
A
B
C
D
K0
A0
B0
C0
D0
K1
A1
B1
C1
D1
K2
A2
B2
C2
D2
K3
A3
B3
C3
D3
其实通过这一个小例子大家也就明白了,join 无非就是合并,默认是横向,还有一个点需要注意的是,我们其实可以通过 join 实现和 merge 一样的效果,但是为了避免混淆,我不会多举其他的例子了,因为我个人认为一般情况下还是用 merge 函数好一些
3. Concat
为了更加全面彻底地了解 Concat 函数,大家可以先从一维的 Numpy Array 开始,首先让我们简单的创建一个矩阵:
# Create a matrix
arr1 = np.arange(9).reshape((3,3))
arr1
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
接着让我们通过 concatenate 函数进行横向拼接:
np.concatenate([arr1,arr1],axis=1)
array([[0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5],
[6, 7, 8, 6, 7, 8]])
再让我们进行纵向拼接:
# Let’s see other axis options
np.concatenate([arr1,arr1],axis=0)
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
有了基础的印象之后,现在让我们看看在 pandas 中是如何操作的:
# Lets create two Series with no overlap
ser1 = Series([0,1,2],index=[‘T’,’U’,’V’])
ser2 = Series([3,4],index=[‘X’,’Y’])
#Now let use concat (default is axis=0)
pd.concat([ser1,ser2])
T 0
U 1
V 2
X 3
Y 4
dtype: int64
在上面的例子中,我们分别创建了两个没有重复 Index 的 Series, 然后用 concat 默认的把它们合并在一起,这时生成的依然是 Series 类型,如果我们把 axis 换成 1,那生成的就是 Dataframe, 像下面一样
pd.concat([ser1,ser2],axis=1,sort =True) # sort=Ture 是默认的,pandas 总是默认 index 排序
0
1
T
0.0
NaN
U
1.0
NaN
V
2.0
NaN
X
NaN
3.0
Y
NaN
4.0
我们还可以指定在哪些 index 上进行 concat:
pd.concat([ser1,ser2],axis=1,join_axes=[[‘U’,’V’,’Y’]])
0
1
U
1.0
NaN
V
2.0
NaN
Y
NaN
4.0
也可以给不同组的 index 加一层标签
pd.concat([ser1,ser2],keys=[‘cat1′,’cat2’])
cat1 T 0
U 1
V 2
cat2 X 3
Y 4
dtype: int64
如果把 axis 换成是 1,那么 keys 就会变成 column 的名字:
pd.concat([ser1,ser2],axis=1,keys=[‘cat1′,’cat2’],sort=True)
cat1
cat2
T
0.0
NaN
U
1.0
NaN
V
2.0
NaN
X
NaN
3.0
Y
NaN
4.0
如果是两个现成的 dataframe 直接进行 concat 也是一样:
dframe1 = DataFrame(np.random.randn(4,3), columns=[‘X’, ‘Y’, ‘Z’])
dframe2 = DataFrame(np.random.randn(3, 3), columns=[‘Y’, ‘Q’, ‘X’])
dframe1
X
Y
Z
0
1.119976
-0.853960
0.027451
1
-0.536831
0.982092
-0.157650
2
-0.219322
-1.489809
1.607735
3
0.767249
-1.661912
0.038837
dframe2
Y
Q
X
0
-0.035560
0.875282
-1.630508
1
-0.439484
0.096247
1.335693
2
0.746299
0.568684
1.197015
# 如果没有对应的值,默认为 NaN, 空值
pd.concat([dframe1,dframe2],sort=True)
Q
X
Y
Z
0
NaN
1.119976
-0.853960
0.027451
1
NaN
-0.536831
0.982092
-0.157650
2
NaN
-0.219322
-1.489809
1.607735
3
NaN
0.767249
-1.661912
0.038837
0
0.875282
-1.630508
-0.035560
NaN
1
0.096247
1.335693
-0.439484
NaN
2
0.568684
1.197015
0.746299
NaN
4. 源码及 Github 地址
今天我为大家主要总结了 pandas 中非常常见的三种方法:
merge
concat
join
大家可以根据自己的实际需要来决定使用哪一种
我把这一期的 ipynb 文件和 py 文件放到了 Github 上,大家如果想要下载可以点击下面的链接:
Github 仓库地址:https://github.com/yaozeliang/pandas_share
这一期就到这里啦,希望大家能够继续支持我,完结,撒花