Pyton中Pandas 合并 101

发布于 2021-02-02 23:25:01

如何执行与pandas(LEFT| RIGHT| FULL)(INNER| OUTER)的联接?
合并后如何为缺失的行添加NaN?
合并后如何去除NaN?
我可以合并索引吗?
与pandas交会吗?
如何合并多个DataFrame?
merge?join?concat?update?Who? What? Why?!
… 和更多。我已经看到这些重复出现的问题,询问有关熊猫合并功能的各个方面。有关合并及其各种用例的大多数信息都分散在数十个措辞不好,无法搜索的帖子中。这里的目的是整理后代的一些更重要的观点。

关注者
0
被浏览
523
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

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

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

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

    • 与不同的列名合并

    • 避免在输出中出现重复的合并键列
    • 在不同条件下与索引合并
    • 有效地使用您的命名索引
    • 合并键作为一个索引,另一个索引
    • 多路合并列和索引(唯一和非唯一)
    • 值得注意的替代品merge和join

    这篇文章不会讲的内容:

    与性能相关的讨论和时间安排(目前)。在适当的地方,最引人注目的是提到更好的替代方案。
    处理后缀,删除多余的列,重命名输出以及其他特定用例。还有其他(阅读:更好)的帖子可以解决这个问题,所以请弄清楚!
    注意
    除非另有说明,否则大多数示例在演示各种功能时会默认使用INNER JOIN操作。

    此外,可以复制和复制此处的所有DataFrame,以便您可以使用它们。另外,请参阅这篇文章 ,了解如何从剪贴板读取DataFrame。

    最后,所有JOIN操作的视觉表示都已使用Google绘图进行了手绘。从这里得到启示。

    聊够了,只是告诉我如何使用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
    

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

    一个内连接由下式表示

    注意:
    此规则以及即将发布的附图均遵循以下约定:

    • 蓝色表示合并结果中存在的行
    • 红色表示从结果中排除(即删除)的行
    • 绿色表示缺少的值将在结果中替换为NaN

    要执行INNER JOIN,请调用merge左侧的DataFrame,并指定右侧的DataFrame和联接键(至少)作为参数。

    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
    

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

    甲LEFT OUTER JOIN,或LEFT JOIN由下式表示

    可以通过指定执行此操作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使用from 的键,而缺失的数据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使用了from 的键,而缺失的数据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。

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

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

    如果您需要分两个步骤进行LEFT排除联接和RIGHT排除联接。

    对于不包括JOIN的LEFT,表示为

    首先执行LEFT OUTER 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
    

    同样,对于除权利加入之外,

    (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 has keyLeftrighthas keyRight代替),key则必须指定left_on和right_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
    

    避免在输出中重复键列

    在keyLeftfrom left和keyRightfrom 上进行合并时right,如果只希望输出中的keyLeft或keyRight(但不全部)两者之一,则可以从将索引设置为初步步骤开始。

    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_on和right_on,如适用)。

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

    或者,如果名称不同,

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

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

    • 合并具有Seri​​es on index的DataFrame:请参阅此答案。
    • 此外merge,DataFrame.update和DataFrame.combine_first也用在某些情况下,更新一个数据帧与另一个。

    • pd.merge_ordered 对有序的JOIN是有用的函数。

    • pd.merge_asof(阅读:merge_asOf)对于近似联接很有用。



  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。


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

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

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

    • 与不同的列名合并

    • 避免在输出中出现重复的合并键列
    • 在不同条件下与索引合并
    • 有效地使用您的命名索引
    • 合并键作为一个索引,另一个索引
    • 多路合并列和索引(唯一和非唯一)
    • 值得注意的替代品merge和join

    这篇文章不会讲的内容:

    与性能相关的讨论和时间安排(目前)。在适当的地方,最引人注目的是提到更好的替代方案。
    处理后缀,删除多余的列,重命名输出以及其他特定用例。还有其他(阅读:更好)的帖子可以解决这个问题,所以请弄清楚!
    注意
    除非另有说明,否则大多数示例在演示各种功能时会默认使用INNER JOIN操作。

    此外,可以复制和复制此处的所有DataFrame,以便您可以使用它们。另外,请参阅这篇文章 ,了解如何从剪贴板读取DataFrame。

    最后,所有JOIN操作的视觉表示都已使用Google绘图进行了手绘。从这里得到启示。

    聊够了,只是告诉我如何使用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
    

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

    一个内连接由下式表示

    注意:
    此规则以及即将发布的附图均遵循以下约定:

    • 蓝色表示合并结果中存在的行
    • 红色表示从结果中排除(即删除)的行
    • 绿色表示缺少的值将在结果中替换为NaN

    要执行INNER JOIN,请调用merge左侧的DataFrame,并指定右侧的DataFrame和联接键(至少)作为参数。

    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
    

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

    甲LEFT OUTER JOIN,或LEFT JOIN由下式表示

    可以通过指定执行此操作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使用from 的键,而缺失的数据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使用了from 的键,而缺失的数据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。

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

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

    如果您需要分两个步骤进行LEFT排除联接和RIGHT排除联接。

    对于不包括JOIN的LEFT,表示为

    首先执行LEFT OUTER 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
    

    同样,对于除权利加入之外,

    (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 has keyLeftrighthas keyRight代替),key则必须指定left_on和right_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
    

    避免在输出中重复键列

    在keyLeftfrom left和keyRightfrom 上进行合并时right,如果只希望输出中的keyLeft或keyRight(但不全部)两者之一,则可以从将索引设置为初步步骤开始。

    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_on和right_on,如适用)。

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

    或者,如果名称不同,

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

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

    • 合并具有Seri​​es on index的DataFrame:请参阅此答案。
    • 此外merge,DataFrame.update和DataFrame.combine_first也用在某些情况下,更新一个数据帧与另一个。

    • pd.merge_ordered 对有序的JOIN是有用的函数。

    • pd.merge_asof(阅读:merge_asOf)对于近似联接很有用。

知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看