Pandas中merge()和concat()的区别

162

pd.DataFrame.merge()pd.concat()之间的主要区别是什么?

根据我的了解,它们的区别如下:

  • .merge()只能使用列(加上行索引),语义上适用于数据库风格的操作。 .concat()可以在任一轴上使用,只使用索引,并提供添加分层索引的选项。

  • 顺便提一下,这导致了以下冗余:两者都可以使用行索引组合两个数据框。

  • pd.DataFrame.join()仅为.merge()的某些用例提供了简写。

(Pandas在处理数据分析中非常广泛的用例方面表现出色。但是,探索文档以找出执行特定任务的最佳方法可能会有点令人生畏。)


5
另外,相关内容参见:https://dev59.com/kGEh5IYBdhLWcg3wNxEn#37891437,关于 .merge().join() 的讨论。 - WindChimes
3
在合并、连接和串联方面,我发现这个答案非常清晰地解释了它们如何用于执行相同的操作(它们似乎只是相同功能的替代接口)。感谢您的问题(以及您在评论中链接的答案),我现在终于理解了合并和连接之间的关系。对于串联是否使用不同的实现还不清楚(我想我将不得不查看源代码...)。 - pietroppeter
8个回答

109

两者的高级区别在于,merge()用于基于共同列的值(索引也可以使用,使用left_index=True和/或right_index=True)组合两个(或多个)数据帧,而concat()用于将一个(或多个)数据帧附加到另一个数据帧的下方(或侧面,这取决于axis选项设置为0或1)。

join()用于基于索引将2个数据帧合并;我们可以使用join()而不是使用merge()选项left_index=True

例如:

df1 = pd.DataFrame({'Key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})

df1:
   Key  data1
0   b   0
1   b   1
2   a   2
3   c   3
4   a   4
5   a   5
6   b   6

df2 = pd.DataFrame({'Key': ['a', 'b', 'd'], 'data2': range(3)})

df2:
    Key data2
0   a   0
1   b   1
2   d   2

#Merge
# The 2 dataframes are merged on the basis of values in column "Key" as it is 
# a common column in 2 dataframes

pd.merge(df1, df2)

   Key data1 data2
0   b    0    1
1   b    1    1
2   b    6    1
3   a    2    0
4   a    4    0
5   a    5    0

#Concat
# df2 dataframe is appended at the bottom of df1 

pd.concat([df1, df2])

   Key data1 data2
0   b   0     NaN
1   b   1     NaN
2   a   2     NaN
3   c   3     NaN
4   a   4     NaN
5   a   5     NaN
6   b   6     NaN
0   a   Nan   0
1   b   Nan   1
2   d   Nan   2

那么,这意味着 merge 中的参数 how 的作用和意义与 concat 中的完全不同? - Hemanth Bakaya
1
“concat()”用于将一个(或多个)数据框在垂直方向上(或水平方向上,取决于轴选项是否设置为0或1)进行拼接。但这并不是完全正确的。当使用axis=1时,您正在对索引执行外部或内部连接。请参阅文档:https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html#set-logic-on-the-other-axes - Olsgaard
"merge()" 用于合并两个(或更多)数据框。这对我来说是个新鲜事。如何在不嵌套多个 merge() 调用的情况下合并三个或更多的数据框呢? - MrChadMWood

41

概括来说:

  • .concat()简单地将多个DataFrame垂直堆叠在一起,或在对齐索引后水平拼接。
  • .merge()先对齐两个DataFrame的公共列(s)或索引,然后从每个DataFrame的对齐行中选择剩余的列。

更具体地说,.concat()

  • 是一个顶级 pandas 函数
  • 结合两个或多个 pandas DataFrame,可以垂直或水平组合
  • 在水平组合时仅在索引上对齐
  • 当任何DataFrame包含重复索引时出错
  • 默认为外连接,并提供内部连接选项

.merge()

  • 既作为顶级 pandas 函数,也作为DataFrame方法存在(自 pandas 1.0 起)
  • 仅水平组合两个DataFrame
  • 将调用DataFrame的列(s)或索引与其他DataFrame的列(s)或索引对齐
  • 通过执行笛卡尔积处理连接列或索引上的重复值
  • 默认为内部连接,具有左侧、外部和右侧选项
请注意,当执行 pd.merge(left, right)时,如果left包含两行具有相同值的连接列或索引,则每行将与right的相应行组合,导致笛卡尔积。另一方面,如果使用.concat()来组合列,则我们需要确保在任何一个DataFrame中不存在重复的索引。
实际上:
- 当组合同类型的DataFrame时,首先考虑使用.concat(),而当组合互补的DataFrame时,首先考虑使用.merge()。 - 如果需要垂直合并,请使用.concat()。如果需要通过列水平合并,请使用.merge(),默认情况下会在共同的列上进行合并。
参考:Pandas 1.x Cookbook

15

pd.concatIterable作为其参数,因此不能直接将DataFrame作为其参数。在连接时,DataFrameDimension应沿轴匹配。

pd.merge可以将DataFrame作为其参数,并用于组合两个具有相同列或索引的DataFrame,这不能通过pd.concat来实现,因为它会在DataFrame中显示重复的列。

而join可用于连接具有不同索引的两个DataFrame


8
我喜欢这个答案,因为它指出在拼接数据时应该匹配维度。concat只是将几个数据框垂直/水平地粘合在一起,不会智能识别内容并避免同名列的问题。而merge则会在列名相同时合并这些列。 - gosuto
7
我认为这不是真的。即使上面的答案(由@Abhishek Sawant提供)给出了一个concat的例子,其中维度不匹配。 - michcio1234

10
我目前正在尝试理解pd.DataFrame.merge()pd.concat()之间的基本区别。主要区别是:

pd.concat

适用于两个轴。另一个区别是,pd.concat仅具有inner默认outer连接,而pd.DataFrame.merge()具有leftrightouterinner默认连接。
第三个显著的区别是:pd.DataFrame.merge()在合并具有相同名称的列时,可以设置列后缀,而对于pd.concat则不可能。
使用pd.concat默认情况下你可以将多个数据框的行堆叠在一起(axis=0),当你设置axis=1时,你会模仿pd.DataFrame.merge()函数。
一些有用的pd.concat示例:
df2=pd.concat([df]*2, ignore_index=True) #double the rows of a dataframe

df2=pd.concat([df, df.iloc[[0]]]) # add first row to the end

df3=pd.concat([df1,df2], join='inner', ignore_index=True) # concat two df's

pd.concat 中,默认情况下使用外连接。 https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html - atif93

6
主要区别在于merge和concat之间的区别是,merge允许您执行更结构化的表“join”,而使用concat更广泛且不太结构化。
合并
参考文档,pd.DataFrame.merge将right作为必需参数,您可以将其视为根据某些预定义的结构化连接操作连接左表和右表。请注意参数right的定义。
必需参数
right:DataFrame或命名Series
可选参数
  • how: {‘left’, ‘right’, ‘outer’, ‘inner’},默认为‘inner’
  • on: 标签或列表
  • left_on: 标签或列表,或类似数组
  • right_on: 标签或列表,或类似数组
  • left_index: 布尔值,默认为False
  • right_index: 布尔值,默认为False
  • sort: 布尔值,默认为False
  • suffixes: 元组(str, str),默认为(‘_x’, ‘_y’)
  • copy: 布尔值,默认为True
  • indicator: 布尔值或字符串,默认为False
  • validate: 字符串,可选

重要提示: pd.DataFrame.merge 要求右侧为pd.DataFrame或命名为pd.Series对象。

输出

  • 返回: DataFrame

此外,如果我们查看 pandas 的 Merge Operation 的文档字符串如下:

使用列或行索引作为键,在两个DataFrame或Series对象之间执行数据库(SQL)合并操作。 Concat 请参考文档中的pd.concat,首先注意参数没有命名为table,data_frame,series,matrix等,而是命名为objs。也就是说,您可以传递许多“数据容器”,这些容器定义为: Iterable[FrameOrSeriesUnion],Mapping[Optional[Hashable],FrameOrSeriesUnion] 必需参数
  • objs:序列或映射的Series或DataFrame对象
  • 可选参数
    • axis: {0/’index’, 1/’columns’},默认为0
    • join: {‘inner’, ‘outer’},默认为‘outer’
    • ignore_index: 布尔类型,默认为False
    • keys: 序列,默认为None
    • levels: 序列列表,默认为None
    • names: 列表,默认为None
    • verify_integrity: 布尔类型,默认为False
    • sort: 布尔类型,默认为False
    • copy: 布尔类型,默认为True

    输出

    • 返回值:对象,与objs类型相同

    例子

    代码

    import pandas as pd
    
    v1 = pd.Series([1, 5, 9, 13])
    v2 = pd.Series([10, 100, 1000, 10000])
    v3 = pd.Series([0, 1, 2, 3])
    
    df_left = pd.DataFrame({
        "v1": v1,
        "v2": v2,
        "v3": v3
        })
    df_right = pd.DataFrame({
        "v4": [5, 5, 5, 5],
        "v5": [3, 2, 1, 0]
        })
    
    
    df_concat = pd.concat([v1, v2, v3])
    
    # Performing operations on default
    
    merge_result = df_left.merge(df_right, left_index=True, right_index=True)
    concat_result = pd.concat([df_left, df_right], sort=False)
    print(merge_result)
    print('='*20)
    print(concat_result)
    

    代码输出

       v1     v2  v3  v4  v5
    0   1     10   0   5   3
    1   5    100   1   5   2
    2   9   1000   2   5   1
    3  13  10000   3   5   0
    ====================
         v1       v2   v3   v4   v5
    0   1.0     10.0  0.0  NaN  NaN
    1   5.0    100.0  1.0  NaN  NaN
    2   9.0   1000.0  2.0  NaN  NaN
    3  13.0  10000.0  3.0  NaN  NaN
    0   NaN      NaN  NaN  5.0  3.0
    1   NaN      NaN  NaN  5.0  2.0
    2   NaN      NaN  NaN  5.0  1.0
    

    你可以通过更改 axis 参数,使用 concat 来实现第一个输出(合并)。
    concat_result = pd.concat([df_left, df_right], sort=False, axis=1)
    

    观察以下行为,
    concat_result = pd.concat([df_left, df_right, df_left, df_right], sort=False)
    

    输出;

         v1       v2   v3   v4   v5
    0   1.0     10.0  0.0  NaN  NaN
    1   5.0    100.0  1.0  NaN  NaN
    2   9.0   1000.0  2.0  NaN  NaN
    3  13.0  10000.0  3.0  NaN  NaN
    0   NaN      NaN  NaN  5.0  3.0
    1   NaN      NaN  NaN  5.0  2.0
    2   NaN      NaN  NaN  5.0  1.0
    3   NaN      NaN  NaN  5.0  0.0
    0   1.0     10.0  0.0  NaN  NaN
    1   5.0    100.0  1.0  NaN  NaN
    2   9.0   1000.0  2.0  NaN  NaN
    3  13.0  10000.0  3.0  NaN  NaN
    0   NaN      NaN  NaN  5.0  3.0
    1   NaN      NaN  NaN  5.0  2.0
    2   NaN      NaN  NaN  5.0  1.0
    3   NaN      NaN  NaN  5.0  0.0
    

    使用merge无法执行类似的操作,因为它只允许单个DataFrame或具名Series。

    merge_result = df_left.merge([df_right, df_left, df_right], left_index=True, right_index=True)
    

    输出;

    TypeError: Can only merge Series or DataFrame objects, a <class 'list'> was passed
    

    结论

    您可能已经注意到,“merge”和“concat”之间的输入和输出可能不同。

    正如我在开始时提到的,第一个(主要)区别是,“merge”使用一组受限制的对象和参数执行更结构化的联接操作,而“concat”使用更宽泛的一组对象和参数执行较不严格/更广泛的联接操作。

    总的来说,“merge”对变化/输入的容忍度较低,“concat”则对变化/输入的敏感度较低。 通过使用“concat”,可以实现“merge”,但反之则不一定成立。

    “Merge”操作使用数据框列(或pd.Series对象的名称)或行索引,因为它仅使用这些实体,所以它执行数据框或系列的水平合并,并且不应用垂直操作。

    如果您想了解更多信息,可以深入查看源代码;


    0

    concat方法正是SQLUNION ALL运算符的作用。在Pandas中,你不仅可以沿着索引轴(与SQL中相同)进行UNION ALL操作,还可以沿着列轴进行操作(如果你将两个每个有3列的数据框连接起来,你将得到一个新的有6列的数据框)。joinmerge方法与SQL中的JOIN相同,尽管后者更强大且更常用。


    -1

    只有concat函数具有轴参数。合并是基于共享列中的值将数据框并排组合在一起,因此不需要轴参数。


    -2

    默认情况下:
    join 是列连接
    pd.merge 是列内连接
    pd.concat 是行外连接

    pd.concat:
    接受可迭代参数。因此,它不能直接接受数据框(使用 [df,df2])
    数据框的维度应沿轴匹配

    Join 和 pd.merge:
    可以接受数据框参数

    点击查看图片以了解为什么下面的代码执行相同操作

    df1.join(df2)
    pd.merge(df1, df2, left_index=True, right_index=True)
    pd.concat([df1, df2], axis=1)
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接