引言

说到数据表拼接,就不得不提一下 SQL ,对于熟悉 SQL 的同学来讲,这并不是一个难以理解的概念,数据表之间的关系可以分为以下这三种:

一对一

两个表之间的公共列是一对一的。

这里的示例我们就不用图片了,直接使用代码来做展示,原因嘛就是小编懒的画了:

import pandas as pd
df1 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet1')
print(df1)
# 输出内容
编号 姓名 分数
小明 96
小红 48
小王 72
小刚 72
df2 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet2')
print(df2)
# 输出内容
编号 班级
1
2
3
4

这里可以很直观的看到,这两个表的编号是公共列,并且唯一对应。

如果我们要讲这两个表进行连接操作,需要使用 merge() 方法:

print(pd.merge(df1, df2))
# 输出内容
编号 姓名 分数 班级
小明 96 1
小红 48 2
小王 72 3
小刚 72 4

在我们使用 merge() 方法的时候, merge() 方法会自动寻找两个表中的公共列,并且自动的进行对应操作。

一对多

两个表之间的公共列不是一对一的,而是其中一个表的公共列是唯一的,另一个表的公共列则会有重复的数据。

import pandas as pd
df1 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet1')
print(df1)
# 输出内容
编号 姓名 分数
小明 96
小红 48
小王 72
小刚 72
df3 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet3')
print(df3)
# 输出内容
编号 分数
101
102
103
104
201
202
301
401

从上面这两个 df 中可以看到, df1 中的编号在 df3 中会对应多条数据,我们在对这两个 df 进行连接操作的时候,需要使用属性 on 指明判断的条件:

print(pd.merge(df1, df3, on='编号'))
# 输出内容
编号 姓名 分数_x 分数_y
小明 96 101
小明 96 102
小明 96 103
小明 96 104
小红 48 201
小红 48 202
小王 72 301
小刚 72 401

多对多

两个表之间的公共列都是会有重复数据的,相当于是多个一对多。

注意理解多个一对多,这里的逻辑稍微有点绕,小编在第一次接触 SQL 的时候实际上是无法理解的。

我们这里新建一个 df4 ,新增一个编号为 100 的小黑,还是通过编号对 df4 和 df3 进行连接操作:

df4 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet4')
print(df4)
# 输出结果
编号 姓名 分数
小明 96
小黑 100
小红 48
小王 72
小刚 72
print(pd.merge(df4, df3, on='编号'))
编号 姓名 分数_x 分数_y
小明 96 101
小明 96 102
小明 96 103
小明 96 104
小黑 100 101
小黑 100 102
小黑 100 103
小黑 100 104
小红 48 201
小红 48 202
小王 72 301
小刚 72 401

连接方式

学过 SQL 的同学都知道, SQL 中连接分为内连接、左连接、右连接和外连接,同样在 Pandas 也是一样的。

内连接

内连接就是取两个表中公共的部分,我们重新创建一个 df5 ,在 df5 中只有编号 100 和 200 能和前面的数据保持一致:

df5 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet5')
print(df5)
# 输出结果
编号 姓名 分数
小明 96
小黑 100
小红 48
想不出来叫啥了1 600
想不出来叫啥了2 700
# 内连接
print(pd.merge(df5, df3, on='编号', how='inner'))
# 输出结果
编号 姓名 分数_x 分数_y
小明 96 101
小明 96 102
小明 96 103
小明 96 104
小黑 100 101
小黑 100 102
小黑 100 103
小黑 100 104
小红 48 201
小红 48 202

这里 how 属性是用来指定连接类型的。

左连接

左连接就是已左表为基础,右表像左表上拼数据:

# 左连接
print(pd.merge(df5, df3, on='编号', how='left'))
# 输出结果
编号 姓名 分数_x 分数_y
小明 96 101.0
小明 96 102.0
小明 96 103.0
小明 96 104.0
小黑 100 101.0
小黑 100 102.0
小黑 100 103.0
小黑 100 104.0
小红 48 201.0
小红 48 202.0
想不出来叫啥了1 600 NaN
想不出来叫啥了2 700 NaN

可以看到,在 df5 中,编号 600 和 700 的两条数据在 df3 中没有,所以 分数_y 的值为 NaN 。

右连接

右连接正好和上面的左连接相反,已右表为基础,左表往右表上拼数据:

# 右连接
print(pd.merge(df5, df3, on='编号', how='right'))
# 输出结果
编号 姓名 分数_x 分数_y
小明 96.0 101
小黑 100.0 101
小明 96.0 102
小黑 100.0 102
小明 96.0 103
小黑 100.0 103
小明 96.0 104
小黑 100.0 104
小红 48.0 201
小红 48.0 202
NaN NaN 301
NaN NaN 401

外连接

外连接就是两个表的并集:

# 外连接
print(pd.merge(df5, df3, on='编号', how='outer'))
# 输出结果
编号 姓名 分数_x 分数_y
小明 96.0 101.0
小明 96.0 102.0
小明 96.0 103.0
小明 96.0 104.0
小黑 100.0 101.0
小黑 100.0 102.0
小黑 100.0 103.0
小黑 100.0 104.0
小红 48.0 201.0
小红 48.0 202.0
想不出来叫啥了1 600.0 NaN
想不出来叫啥了2 700.0 NaN
NaN NaN 301.0
NaN NaN 401.0

纵向拼接

顾名思义,纵向拼接就是在纵向上对两个表进行拼接,当然这需要两个表具有相同的结构,前面我们介绍的拼接方式都在横向上进行拼接。

这里我们再加入一个 df6 ,使用 df5 和 df6 演示纵向拼接,在 Pandas 中使用纵向拼接使用的方法是 concat() :

df6 = pd.read_excel("table_join_exp.xlsx", sheet_name='Sheet6')
print(df6)
# 输出结果
编号 姓名 分数
起个名字好难啊 100
起个名字真的难 200
# 纵向拼接
print(pd.concat([df5, df6]))
# 输出结果
编号 姓名 分数
小明 96
小黑 100
小红 48
想不出来叫啥了1 600
想不出来叫啥了2 700
起个名字好难啊 100
起个名字真的难 200

当我们使用 concat() 以后,发现索引还是保留了原有的索引,看着很不舒服,这时我们可以设置参数 ignore_index ,让其不在保留原有索引,而是生成新的索引:

print(pd.concat([df5, df6], ignore_index=True))
# 输出结果
编号 姓名 分数
小明 96
小黑 100
小红 48
想不出来叫啥了1 600
想不出来叫啥了2 700
起个名字好难啊 100
起个名字真的难 200

本篇的分享到这里就算结束,如果有 SQL 基础的同学看起来应该毫无压力,没有基础的同学推荐自己动手试一下,很多看着不是很理解的东西一动手就立马打通任督二脉。