likes
comments
collection
share

Pandas进阶:使用Join、Merge、Concat、Append 合并DataFrame

作者站长头像
站长
· 阅读数 11

Pandas进阶:使用Join、Merge、Concat、Append 合并DataFrame

前言

当我们使用DataFrame进行合并操作时主要会用到以下四种方法:

  • Join
  • Merge
  • Concat
  • Append 不太熟悉的朋友可能见到这么多的方法一时乱了手脚,从而无从下手。那么在这篇文章中我们将结合具体的例子详细阐述这几个方法之间的相同点与不同点,让你不再对这四个方法陌生,同时向着数据分析的路上迈出坚实的一步。

连接方式

提到合并,一定绕不开一个概念,就是合并的方式。Pandas中的合并操作的连接方式类似于数据库查询中的left、right、inner、outer连接。

在我们开始学习这几种合并函数之前,我们先来学习下连接方式的相关知识吧!

俗话说,文不如图,leftright连接的具体示例如下所示:

Pandas进阶:使用Join、Merge、Concat、Append 合并DataFrame

innerouter连接的具体示例如下所示:

Pandas进阶:使用Join、Merge、Concat、Append 合并DataFrame

按图例所示,我们可以清晰的看出这四种连接方式之间的区别。left连接方式是由左表的某一列为合并基准(图中为姓名列),当两个表按照这种方式合并时,只有右表中的姓名和左表中的姓名匹配时(Mike、Nana),最终才会合并到左表中显示。right连接方式则和left相反,是按照右表的某一列为基准,左表中的姓名和右表中的姓名匹配时,最终合并到右表显示。inner通常叫做内连接,最终的显示结果为两张表中的相同列。outer是外连接,其结果为两张表的数据全部融合到一起,你有我无要保留,我有你无亦保留,你我共同的就合并为一行数据。

一. Join

Join 是基于行索引来进行的合并操作。如果你的需求是让两个DataFrame合并,且是依据两个DF的索引来进行合并的,那么显然Join是最好的选择,下面我们一起来看一看如何使用Join方法:

df.join(other, on=None, how="left", lsuffix="", rsuffix="", sort=False)

参数说明

  • other 可传入DataFrame、Series或由DataFrame组成的列表。other的行索引必须要和df中的某一列所匹配(如果出现两列数据类型不匹配的情况会报异常。)才可执行连接操作。如果传入Seires时,则必须传入Name属性。

  • on 默认为None,也就是使用dfother行索引列进行连接。同时也可以传入df中的列名进行连接,这种情况必须要保证other的索引必须和传入的df中的列名所对应。

  • how 连接方式,可选择:left、right、inner、outer。默认为left。

  • lsuffix 代表df的重叠列后缀。默认为空字符串。若dfother中有相同的列,则必须传入。

  • rsuffix 代表other的重叠列后缀。默认为空字符串。若dfother中有相同的列,则必须传入。

  • sort 通过联接关键字按字典顺序对结果DataFrame进行排序。 如果为False,则联接键的顺序取决于联接类型(how关键字)。默认为False

使用示例

  1. 简单合并(使用默认left连接方式)
df1 = pd.DataFrame({'column1': [1, 2], 'column2': [3, 4]}, index=list('BA'))
df2 = pd.DataFrame({'column1': [5, 6], 'column2': [7, 8]}, index=list('BC'))

"""
df1:                      df2:
   column1  column2      |      column1  column2
B        1        3      | B          2        7
A        2        4      | C          5        8
"""
df = df1.join(df2, lsuffix='_L', rsuffix='_R') # 通过left方式合并

Output:
   column1_L  column2_L  column1_R  column2_R
B          1          3        2.0      7.0
A          2          4        NaN      NaN

上述例子中由于两个DF中有相同的列column,所以必须传入lsuffix和rsuffix参数来更改重叠列名的后缀(也可只传入一个重叠后缀,另一个则原封不动的显示原有的列名)

  1. 使用某一列字段进行合并:
# 依据df1中的column1列进行排序
df = df1.join(df2.set_index(df2['column1']), on='column1', lsuffix='_L', rsuffix='_R', how='left')

Output:
   column1_L  column2_L  column1_R  column2_R
B          1          3        NaN      NaN
A          2          4        2.0      7.0

on 字段只是指定了df1中的合并字段,并不能应用到df2中(df2还是使用索引作为基准进行合并),所以为了保持字段一致性,我们使用了set_index方法把df2中的索引列更换为colum1

二. Merge

Merge 则是基于键来进行两个DF的合并。举个例子,假设DF_A中包含index(行索引列),sid,name,math四列,DF_B中包含index,sid,chinese三列,且DF_A和DF_B的合并依据为sid,那么在这种情况下,你可以选择使用Merge。(Join也可行,只需把两个DF的sid列赋值给索引列即可,但既然Merge就是应用于通过键的合并,我们为何不用Merge呢?)。以下是Merge的使用方法:

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 进行合并时的左DataFrame对象

  • right 进行合并时的右DataFrame对象

  • how 连接方式,可选择:left、right、inner、outer。默认为inner。

  • on 指定按照哪个键(列名)作为基准进行合并。传入的键必须同时存在于两个DF中,否则会报错。如果没有传入任何值,且left_indexright_index的值都为False,则按照两个DF中相同的列作为基准进行合并。

  • left_on 左侧DF的基准列。使用这个参数一般是由于两个DF中没有相同的列,则需指定左右两侧进行合并的基准列。

  • right_on 右侧DF的基准列。

  • left_index 是否使用左侧的行索引列作为基准。相当于left_on中传入行索引列作为基准列

  • right_index 是否使用左侧的行索引列作为基准。相当于right_on中传入行索引列作为基准列

  • suffixes 设定重叠的列名的后缀。类型字符串类元组,默认重叠左侧后缀为_x,重叠右侧为_y

  • sort 按连接键对结果DataFrame进行排序。默认情况下为True,在许多情况下,设置为False会大大提高性能。

  • validate 默认无。如果指定,则检查merge是否为指定类型。

    • “one_to_one” or “1:1”: 检查合并键在左右数据集中是否唯一
    • “one_to_many” or “1:m”: 检查合并键在左数据集中是否唯一
    • “many_to_one” or “1:1”: 检查合并键在右数据集中是否唯一
    • “many_to_many” or “m:m”: 允许,但不会导致检查。
  • indicator 在输出的DF中添加一列名为_merge的列,其中包含有关每一行来源的信息。对于仅出现在左侧DF的indicator的值为left_only,仅出现在右侧DF的indicator的值为right_only, 同时存在两个DF的indicator的职位both

使用示例

  1. 使用Merge进行简单合并操作:
# 通过left方式进行合并
df = pd.merge(df1, df2, on='column1', how='left')

Output:
   column1  column2_x  column2_y
0        1          3        NaN
1        2          4        7.0

# 通过outer方式进行合并,同时打开指示器,显示合并后的数据来源情况
df = pd.merge(df1, df2, on='column1', how='outer', indicator=True)

Output:
   column1  column2_x  column2_y      _merge
0        1        3.0        NaN   left_only
1        2        4.0        7.0        both
2        5        NaN        8.0  right_only
  1. 两列的合并字段值不一样的情况:
# 通过outer方式进行,左表根据'column1', 右表根据'column2',合并同时打开指示器,显示合并后的数据来源情况
df = pd.merge(df1, df2, left_on='column1', right_on='column2', how='outer', indicator=True)

Output:
   column1_x  column2_x  column1_y  column2_y      _merge
0        1.0        3.0        NaN        NaN   left_only
1        2.0        4.0        NaN        NaN   left_only
2        NaN        NaN        2.0        7.0  right_only
3        NaN        NaN        5.0        8.0  right_only

三. Concat

如果你想连接多个(两个或以上)df对象,且需求是按轴(横向或纵向)进行合并,那么你可以试试使用concat方法。

pd.concat(objs, axis=0, join="outer", ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort: bool = False, copy=True)
  • objs Series或DataFrame对象的序列或映射。 如果传递了dict,则除非传递了已排序的键,否则它将用作keys参数,在这种情况下,将选择值(请参见下文)。 除非所有对象都为None,否则所有None对象都将被静默删除,在这种情况下将引发ValueError。

  • axis 选择按哪个轴进行合并,0:索引轴(纵向合并,类似于以下要提到的append方法),1:Columns轴(横向合并)。默认为0

  • join 连接方式,可选择:inner、outer。默认为outter。与Join、Merge不同,使用Concat合并时只支持内连接和外连接方法。

  • ignore_index 布尔值,默认为False. 忽略合并轴的索引值。按0轴合并时,合并后的行索引值将重新按照0.1.2...N赋值。按1轴合并后,Columns(列名)将会按照range(0,df.shape[0])赋值。

  • keys 用于构建连接轴上的层次化索引(按数据的来源分层)。

  • verify_integrity 布尔值,默认为False(允许出现重复项). 检查结果对象在所选轴上的重复情况。

  • levels 用作层次或索引中的各级别的索引。一般是用作多层次索引的,实际使用中并不常用。感兴趣的小伙伴可以了解下Pandas的多层次索引

  • names 用于命名生成的多层次索引.名称列表的长度应与生成的多层次索引中的级别数相匹配.

  • sort 默认不排序。如果joinouter时尚未对齐未连接轴,则对它进行排序。当join = inner且保留了顺序时,排序将不起作用。

用法示例

  1. 简单合并(横向和纵向)
df = pd.concat([df1, df2]) #默认为纵向合并(沿着索引列,也就是Y轴, 合并基准为列名一致,显示到一列中去)

Output:
   column1  column2
B        1        3
A        2        4
B        2        7
C        5        8

df = pd.concat([df1, df2], axis=1) #横向合并(沿着Columns列,也就是X轴, 合并基准为索引一致,显示到一行中去)

Output:
   column1  column2  column1  column2
B      1.0      3.0      2.0      7.0
A      2.0      4.0      NaN      NaN
C      NaN      NaN      5.0      8.0

df = pd.concat([df1, df2], axis=1, join='inner') #横向合并,最后显示索引相同的列

Output:
   column1  column2  column1  column2
B        1        3        2        7

df = pd.concat([df1, df2], ignore_index=True) #纵向合并,合并后轴(索引列)重新赋值

Output:
   column1  column2
0        1        3
1        2        4
2        2        7
3        5        8

四. Append

在四种合并方式中,最简单易用的合并方法要数append了,不过正因为简单易用,其支持的操作也比前边三个老大哥少了很多,常规操作,我们还是先来看看参数详解:

df.append(other, ignore_index=False, verify_integrity=False, sort=False)
  • other 可传入DataFrame、Series或由DataFrame(Series)组成的列表(适用于多DF(Series)合并到df中的情况)。

  • ignore_index 布尔值,默认为False. 忽略合并后的索引值。也就是将合并后df的索引值重新赋值为range(0,df.shape[0])

  • verify_integrity 布尔值,默认为False(允许出现重复项). 检查合并后的结果对象索引列的重复情况。

  • sort 默认不排序。如果joinouter时尚未对齐未连接轴,则对它进行排序。当join = inner且保留了顺序时,排序将不起作用。

用法示例

  1. 简单合并(横向和纵向)
df = df1.append(df2) #合并

Output:
   column1  column2
B        1        3
A        2        4
B        2        7
C        5        8

df = df1.append([df2, df2], ignore_index=True) #合并两次df2,索引重新赋值

Output:
   column1  column2
0        1        3
1        2        4
2        2        7
3        5        8
4        2        7
5        5        8

简单总结

Join:基于索引进行合并操作,支持两个或以上的DF对象同时合并。

Merge: 基于键(可以是索引,亦可以是其他列名)进行合并操作,仅支持两个DF对象进行合并操作。

Concat:基于轴(横向或纵向)进行排序,支持两个或以上的DF对象同时合并。

append:和concat类似,但仅支持纵向扩展,支持两个或以上的DF对象同时合并。

由于四个方法中参数过于多,所以本节的例子只是给出了基本的使用情况,至于更多的组合用法还请读者自行在自己的IDE中学习使用,本节的学习至此也将告一段落,谢谢各位的捧场,有任何问题都可以在评论区留言,感谢!