熊猫合并101

时间:2018-12-06 06:41:16

标签: python pandas join merge

  • 如何与熊猫进行(LEFT | RIGHT | FULL)(INNER | OUTER)联接?
  • 如何在合并后为缺失的行添加NaN?
  • 合并后如何去除NaN?
  • 我可以合并索引吗?
  • Cross join with pandas?
  • 如何合并多个DataFrame?
  • mergejoinconcatupdate?谁?什么?为什么?!

...等等。我已经看到这些重复出现的问题,询问有关熊猫合并功能的各个方面。如今,有关合并及其各种用例的大多数信息都分散在数十个措辞不好,无法搜索的帖子中。这里的目的是整理一些关于后代的更重要的观点。

此QnA旨在作为一系列有关常见熊猫习语的有用用户指南的下一部分(请参阅this post on pivotingthis post on concatenation,我将在稍后进行介绍)。

请注意,该帖子不是 ,它是documentation的替代内容,因此也请阅读!一些示例是从那里获取的。

5 个答案:

答案 0 :(得分:221)

这篇文章旨在为读者提供有关SQL风格与熊猫的合并,使用方法以及何时不使用它的入门知识。

特别是,这是这篇文章的内容:

  • 基本知识-联接类型(左,右,外,内)

    • 合并不同的列名
    • 避免在输出中出现重复的合并键列
  • 在不同条件下合并索引
    • 有效使用您的命名索引
    • 将键合并为一个键的索引,并合并另一个键的列
  • Multiway合并列和索引(唯一和非唯一)
  • mergejoin的显着替代方式

该帖子不会涉及的内容:

  • 与性能有关的讨论和时间安排(目前)。在适当的地方,最引人注目的是提到更好的替代方案。
  • 处理后缀,删除多余的列,重命名输出以及其他特定用例。还有其他(阅读:更好)的帖子可以解决这个问题,所以请弄清楚!
  

注意
  除非另有说明,否则大多数示例在演示各种功能时都会默认使用INNER JOIN操作。

     

此外,此处的所有DataFrame都可以复制和复制,因此   你可以和他们一起玩。另外,请参见this post   关于如何从剪贴板读取DataFrame的信息。

     

最后,JOIN操作的所有可视化表示都是借来的   感谢这篇文章   https://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins

足够多的谈话,请教我如何使用merge

设置

np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})    
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})

left

  key     value
0   A  1.764052
1   B  0.400157
2   C  0.978738
3   D  2.240893

right

  key     value
0   B  1.867558
1   D -0.977278
2   E  0.950088
3   F -0.151357

为简单起见,键列具有相同的名称(目前)。

内部联接

表示

  

注意
  A是指left DataFrame B中join列的键   引用right DataFrame中join列中的键,并且相交   代表leftright共同的键。   阴影区域表示JOIN结果中存在的键。此惯例将始终遵循。请记住, Venn图并不是JOIN操作的100%准确表示,因此请加点盐。

要执行内部联接,请调用pd.merge,以指定左侧的DataFrame,右侧的DataFrame和联接键。

pd.merge(left, right, on='key')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278

这仅返回leftright中共享同一密钥(在此示例中为“ B”和“ D”)的行。

在较新的熊猫版本(v0.21左右)中,merge现在是一阶函数,因此可以调用DataFrame.merge

left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278

左外部联接或左联接由

表示

这可以通过指定how='left'来执行。

left.merge(right, on='key', how='left')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278

请注意此处NaN的位置。如果指定how='left',则仅使用left中的键,而right中的丢失数据将被NaN替换。

并且类似地,对于 RIGHT OUTER JOIN 或RIGHT JOIN这是...

...指定how='right'

left.merge(right, on='key', how='right')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278
2   E       NaN  0.950088
3   F       NaN -0.151357

这里,使用了right中的密钥,而left中的丢失数据被NaN替换。

最后,对于 FULL OUTER JOIN ,由

给出

指定how='outer'

left.merge(right, on='key', how='outer')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278
4   E       NaN  0.950088
5   F       NaN -0.151357

这使用两个框架中的关键点,并且为两个框架中缺少的行插入NaN。

文档很好地总结了这些各种合并:

enter image description here

其他联接-左排除,右排除和全排除/ ANTI联接

如果您需要分两个步骤不包含JOIN的不包含JOIN的

对于LEFT(不包括JOIN),表示为

首先执行左外部联接,然后过滤(不包括!)仅来自left的行,

(left.merge(right, on='key', how='left', indicator=True)
     .query('_merge == "left_only"')
     .drop('_merge', 1))

  key   value_x  value_y
0   A  1.764052      NaN
2   C  0.978738      NaN

在哪里

left.merge(right, on='key', how='left', indicator=True)

  key   value_x   value_y     _merge
0   A  1.764052       NaN  left_only
1   B  0.400157  1.867558       both
2   C  0.978738       NaN  left_only
3   D  2.240893 -0.977278       both

同样,对于不包含权利的JOIN,

(left.merge(right, on='key', how='right', indicator=True)
     .query('_merge == "right_only"')
     .drop('_merge', 1))

  key  value_x   value_y
2   E      NaN  0.950088
3   F      NaN -0.151357

最后,如果要求您进行合并,而该合并仅保留左侧或右侧的键,而不同时保留两者(IOW,执行 ANTI-JOIN ),

您可以通过类似的方式进行操作

(left.merge(right, on='key', how='outer', indicator=True)
     .query('_merge != "both"')
     .drop('_merge', 1))

  key   value_x   value_y
0   A  1.764052       NaN
2   C  0.978738       NaN
4   E       NaN  0.950088
5   F       NaN -0.151357

键列的不同名称

如果键列的名称不同(例如,left具有keyLeft,而right具有keyRight而不是key,那么您将拥有将left_onright_on指定为参数,而不是on

left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)

left2

  keyLeft     value
0       A  1.764052
1       B  0.400157
2       C  0.978738
3       D  2.240893

right2

  keyRight     value
0        B  1.867558
1        D -0.977278
2        E  0.950088
3        F -0.151357

left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')

  keyLeft   value_x keyRight   value_y
0       B  0.400157        B  1.867558
1       D  2.240893        D -0.977278

在输出中避免重复的键列

在合并keyLeft中的leftkeyRight中的right时,如果您只想要keyLeftkeyRight中的一个(但(不是全部)在输出中,您可以先将索引设置为第一步。

left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')

    value_x keyRight   value_y
0  0.400157        B  1.867558
1  2.240893        D -0.977278

将此与之前的命令输出(这是left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')的输出)进行对比,您会发现keyLeft丢失了。您可以根据将哪个帧的索引设置为关键字来确定要保留的列。例如,当执行某些OUTER JOIN操作时,这可能很重要。

仅合并DataFrames

中的一个列

例如,考虑

right3 = right.assign(newcol=np.arange(len(right)))
right3
  key     value  newcol
0   B  1.867558       0
1   D -0.977278       1
2   E  0.950088       2
3   F -0.151357       3

如果只需要合并“ new_val”(不包含任何其他列),则通常可以在合并之前只是将其子集作为子集:

left.merge(right3[['key', 'newcol']], on='key')

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

如果您要进行左侧外部联接,则性能更高的解决方案将涉及map

# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

如前所述,这类似于但快于

left.merge(right3[['key', 'newcol']], on='key', how='left')

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

合并到多列

要加入不止一列,请为on(或视情况选择left_onright_on)指定一个列表。

left.merge(right, on=['key1', 'key2'] ...)

或者,如果名称不同,

left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])

其他有用的merge*操作和功能

本节仅介绍最基本的知识,目的只是为了激发您的胃口。有关更多示例和案例,请参见documentation on merge, join, and concat以及功能说明的链接。


基于索引的* -JOIN(+索引列merge s)

设置

np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])    
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'

left
           value
idxkey          
A      -0.602923
B      -0.402655
C       0.302329
D      -0.524349

right

           value
idxkey          
B       0.543843
D       0.013135
E      -0.326498
F       1.385076

通常,索引合并看起来像这样:

left.merge(right, left_index=True, right_index=True)


         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

对索引名称的支持

如果您的索引已命名,则v0.23用户还可以将级别名称指定为on(或根据需要指定left_onright_on)。

left.merge(right, on='idxkey')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

合并一个索引,另一个索引列

可以(非常简单)使用一个索引和另一个列进行合并。例如,

left.merge(right, left_on='key1', right_index=True)

反之亦然(right_on=...left_index=True)。

right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2

  colkey     value
0      B  0.543843
1      D  0.013135
2      E -0.326498
3      F  1.385076

left.merge(right2, left_index=True, right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

在这种特殊情况下,left的索引已命名,因此您也可以将索引名与left_on一起使用,如下所示:

left.merge(right2, left_on='idxkey', right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

DataFrame.join
除了这些,还有另一个简洁的选择。您可以使用DataFrame.join,它默认情况下在索引上联接。 DataFrame.join默认情况下不做LEFT OUTER JOIN,因此这里how='inner'是必需的。

left.join(right, how='inner', lsuffix='_x', rsuffix='_y')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

请注意,我需要指定lsuffixrsuffix参数,因为否则join会出错:

left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')

由于列名相同。如果它们的名称不同,这将不是问题。

left.rename(columns={'value':'leftvalue'}).join(right, how='inner')

        leftvalue     value
idxkey                     
B       -0.402655  0.543843
D       -0.524349  0.013135

pd.concat
最后,作为基于索引的联接的替代方法,您可以使用pd.concat

pd.concat([left, right], axis=1, sort=False, join='inner')

           value     value
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

如果需要FULL OUTER JOIN(默认),请省略join='inner'

pd.concat([left, right], axis=1, sort=False)

      value     value
A -0.602923       NaN
B -0.402655  0.543843
C  0.302329       NaN
D -0.524349  0.013135
E       NaN -0.326498
F       NaN  1.385076

有关更多信息,请参见this canonical post on pd.concat by @piRSquared


概括:merge多个数据框

设置

np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})    
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C]   

通常,将多个DataFrame合并在一起时会出现这种情况。天真的,这可以通过链接merge调用来完成:

A.merge(B, on='key').merge(C, on='key')

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

但是,对于许多DataFrame来说,这很快就变得一发不可收拾。此外,可能有必要归纳为未知数量的DataFrame。为此,functools.reduce是一个经常使用的简单技巧,您可以使用它来实现INNER JOIN,如下所示:

from functools import reduce
reduce(pd.merge, dfs)

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

请注意,“键”列以外的每一列都应以不同的方式命名,以便立即使用。否则,您可能需要使用lambda

对于完全外部联接,可以使用curry functools.partial pd.merge

from functools import partial
outer_merge = partial(pd.merge, how='outer')
reduce(outer_merge, dfs)

  key    valueA    valueB  valueC
0   A  1.764052       NaN     NaN
1   B  0.400157  1.867558     NaN
2   C  0.978738       NaN     1.0
3   D  2.240893 -0.977278     1.0
4   E       NaN  0.950088     1.0
5   F       NaN -0.151357     NaN
6   J       NaN       NaN     1.0

您可能已经注意到,它非常强大-您还可以在合并过程中使用它来控制列名。只需根据需要添加更多关键字参数:

partial(pd.merge, how='outer', left_index=True, right_on=...)

替代方法:pd.concat
如果您的列值是唯一的,那么使用pd.concat是有意义的,这比一次两次的多路合并要快。

pd.concat([
    df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

对唯一索引进行多路合并

如果要在唯一索引上合并多个DataFrame,则应该再次选择pd.concat以获得更好的性能。

# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')
dfs2 = [A2, B2, C2]

pd.concat(dfs2, axis=1, sort=False, join='inner')

       valueA    valueB  valueC
key                            
D    2.240893 -0.977278     1.0

与往常一样,省略join='inner'进行FULL OUTER JOIN。

对具有重复项的索引进行多路合并

concat速度很快,但也有缺点。它无法处理重复项。

A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})

pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)

在这种情况下,join是最佳选择,因为它可以处理非唯一索引(join在后​​台调用merge)。

# For inner join. For left join, omit the "how" argument.
A3.set_index('key').join([B2, C2], how='inner')

       valueA    valueB  valueC
key                            
D    1.454274 -0.977278     1.0
D    0.761038 -0.977278     1.0

答案 1 :(得分:10)

pd.concat([df0, df1], kwargs)的补充视觉视图。 我之所以这么做是由于axis=0axis=1,因为它不像df.mean()df.apply(foo)

那样直观

on pd.concat([df0, df1])

答案 2 :(得分:5)

在这个答案中,我将考虑pandas.concat的实际示例。

请考虑以下具有相同列名的DataFrames

Preco2018 ,大​​小为(8784,5)

DataFrame 1

Preco 2019 ,大​​小为(8760,5)

DataFrame 2

具有相同的列名。

您可以使用pandas.concat简单地组合它们

import pandas as pd

frames = [Preco2018, Preco2019]

df_merged = pd.concat(frames)

这会导致以下尺寸的DataFrame(17544,5)

DataFrame result of the combination of two dataframes

如果您想可视化,它最终会像这样

How concat works

Source

答案 3 :(得分:0)

本文将涉及以下主题:

  • 如何正确归纳为多个DataFrame(以及为什么merge在这里有缺点)
  • 合并唯一键
  • 合并非取消键

BACK TO TOP



泛化为多个DataFrames

通常,将多个DataFrame合并在一起时会出现这种情况。天真的,这可以通过链接merge调用来完成:

df1.merge(df2, ...).merge(df3, ...)

但是,对于许多DataFrame来说,这很快就变得一发不可收拾了。此外,可能有必要归纳为未知数量的DataFrame。

在这里,我介绍pd.concat用于 unique 键上的多方联接,以及{{11}}用于 unique 键上的多方联接。 。首先,设置。

DataFrame.join

在唯一键上进行多路合并

如果键(此处的键可以是列或索引)是唯一的,则可以使用# Setup. np.random.seed(0) A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)}) B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)}) C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)}) dfs = [A, B, C] # Note, the "key" column values are unique, so the index is unique. A2 = A.set_index('key') B2 = B.set_index('key') C2 = C.set_index('key') dfs2 = [A2, B2, C2] 。请注意, pd.concat在索引上联接DataFrames

pd.concat

省略# merge on `key` column, you'll need to set the index before concatenating pd.concat([ df.set_index('key') for df in dfs], axis=1, join='inner' ).reset_index() key valueA valueB valueC 0 D 2.240893 -0.977278 1.0 # merge on `key` index pd.concat(dfs2, axis=1, sort=False, join='inner') valueA valueB valueC key D 2.240893 -0.977278 1.0 进行FULL OUTER JOIN。请注意,您不能指定LEFT或RIGHT OUTER联接(如果需要这些联接,请使用join='inner',如下所述)。


对具有重复项的键进行多路合并

join速度很快,但也有缺点。它无法处理重复项。

concat
A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})

在这种情况下,我们可以使用pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner') ValueError: Shape of passed values is (3, 4), indices imply (3, 2) ,因为它可以处理非唯一键(请注意,join在其索引上联接了DataFrames;它在幕后调用join并执行了左外联接,除非另有说明)。

merge


继续阅读

跳至“熊猫合并101”中的其他主题以继续学习:

*您在这里

答案 4 :(得分:0)

本文将涉及以下主题:

  • 在不同条件下合并索引
      基于索引的联接的
    • 选项:mergejoinconcat
    • 合并索引
    • 合并一个索引,另一个列
  • 有效使用命名索引来简化合并语法

BACK TO TOP



基于索引的联接

TL; DR

有一些选项,根据用途,某些选项比其他选项更简单 情况。

  1. DataFrame.mergeleft_indexright_index(或left_onright_on使用名称索引)
    • 支持内部/左/右/全
    • 一次只能加入两个
    • 支持列-列,索引-列,索引-索引联接
  2. DataFrame.join(加入索引)
    • 支持内部/左侧(默认)/右侧/完整
    • 可以一次加入多个DataFrames
    • 支持索引-索引连接
  3. pd.concat(加入索引)
    • 支持内部/完整(默认)
    • 可以一次加入多个DataFrames
    • 支持索引索引连接

索引到索引连接

设置和基础

import pandas as pd
import numpy as np

np.random.seed([3, 14])
left = pd.DataFrame(data={'value': np.random.randn(4)}, 
                    index=['A', 'B', 'C', 'D'])    
right = pd.DataFrame(data={'value': np.random.randn(4)},  
                     index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'

left
           value
idxkey          
A      -0.602923
B      -0.402655
C       0.302329
D      -0.524349

right
 
           value
idxkey          
B       0.543843
D       0.013135
E      -0.326498
F       1.385076

通常,索引上的内部联接如下所示:

left.merge(right, left_index=True, right_index=True)

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

其他联接遵循类似的语法。

重要的选择

  1. DataFrame.join 默认为索引上的联接。 DataFrame.join默认情况下不做LEFT OUTER JOIN,因此how='inner'在这里是必需的。

     left.join(right, how='inner', lsuffix='_x', rsuffix='_y')
    
              value_x   value_y
     idxkey                    
     B      -0.402655  0.543843
     D      -0.524349  0.013135
    

    请注意,我需要指定lsuffixrsuffix参数,因为否则join会出错:

     left.join(right)
     ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
    

    由于列名相同。如果它们的名称不同,这将不是问题。

     left.rename(columns={'value':'leftvalue'}).join(right, how='inner')
    
             leftvalue     value
     idxkey                     
     B       -0.402655  0.543843
     D       -0.524349  0.013135
    
  2. pd.concat 联接到索引上,并且可以一次联接两个或多个DataFrame。默认情况下,它会进行完全外部联接,因此这里需要how='inner'

     pd.concat([left, right], axis=1, sort=False, join='inner')
    
                value     value
     idxkey                    
     B      -0.402655  0.543843
     D      -0.524349  0.013135
    

    有关concat的更多信息,请参见this post


列连接索引

要使用左索引,右列执行内部联接,您将结合使用DataFrame.mergeleft_index=True的{​​{1}}。

right_on=...

其他联接遵循类似的结构。请注意,只有right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1) right2 colkey value 0 B 0.543843 1 D 0.013135 2 E -0.326498 3 F 1.385076 left.merge(right2, left_index=True, right_on='colkey') value_x colkey value_y 0 -0.402655 B 0.543843 1 -0.524349 D 0.013135 才能执行索引到列的联接。您可以在多列上联接,前提是左侧的索引级别数目等于右侧的列数目。

mergejoin无法混合合并。您需要使用DataFrame.set_index将索引设置为先行步骤。


有效使用命名索引[pandas> = 0.23]

如果您的索引是命名的,那么从熊猫> = 0.23开始,concat允许您将索引名称指定为DataFrame.merge(或根据需要指定onleft_on

right_on

对于上一个与左索引,右列合并的示例,可以将left.merge(right, on='idxkey') value_x value_y idxkey B -0.402655 0.543843 D -0.524349 0.013135 与左索引名称结合使用:

left_on


继续阅读

跳至“熊猫合并101”中的其他主题以继续学习:

*您在这里