问题:熊猫合并101
- 如何执行与熊猫(LEFT|RIGHT|FULL)(INNER|OUTER)的联接?
- 合并后如何为缺失的行添加NaN?
- 合并后如何去除NaN?
- 我可以合并索引吗?
- 与大熊猫交叉交往?
- 如何合并多个DataFrame?
- merge?- join?- concat?- update?WHO?什么?为什么?!
… 和更多。我已经看到这些重复出现的问题,询问有关熊猫合并功能的各个方面。如今,有关合并及其各种用例的大多数信息都分散在数十个措辞不好,无法搜索的帖子中。这里的目的是整理后代的一些更重要的观点。
本QnA是下一章有关大熊猫习语的有用的用户指南中的下一部分(请参阅有关透视的这篇文章和有关串联的这篇文章,我将在以后进行探讨)。
请注意,本文并非旨在代替文档,因此也请阅读!一些示例是从那里获取的。
回答 0
这篇文章旨在为读者提供有关SQL风格的与熊猫的合并,使用方法以及何时不使用它的入门。
特别是,这是这篇文章的内容:
- 基础-联接类型(左,右,外,内) - 与不同的列名合并
- 避免在输出中出现重复的合并键列
 
- 在不同条件下与索引合并 
- 有效地使用您的命名索引
- 合并键作为一个索引,另一个索引
 
- 多路合并列和索引(唯一和非唯一)
- 值得注意的替代品merge和join
这篇文章不会讲的内容:
- 与性能相关的讨论和时间安排(目前)。在适当的地方,最引人注目的是提到更好的替代方案。
- 处理后缀,删除多余的列,重命名输出以及其他特定用例。还有其他(阅读:更好)的帖子可以解决这个问题,所以请弄清楚!
注意
除非另有说明,否则大多数示例在演示各种功能时会默认使用INNER JOIN操作。此外,可以复制和复制此处的所有DataFrame,以便您可以使用它们。另外,请参阅这篇文章 ,了解如何从剪贴板读取DataFrames。
最后,已使用Google绘图手工绘制了JOIN操作的所有可视表示形式。从这里得到启示。
聊够了,只是告诉我如何使用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
这仅返回来自left并right共享一个公共密钥的行(在本示例中为“ 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 的键,而rightNaN替换缺少的数据。
同样,对于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-Exclusive JOIN和RIGHT-Exclusive JOIN。
对于不包括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
键列的不同名称
如果键列的名称不同(例如,lefthas keyLeft和righthas 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*操作和功能
- 合并具有Series on index的DataFrame:请参阅此答案。
- 此外 - merge,- DataFrame.update和- DataFrame.combine_first也用在某些情况下,更新一个数据帧与另一个。
- pd.merge_ordered是有序JOIN的有用函数。
- pd.merge_asof(阅读:merge_asOf)对于近似联接很有用。
本节仅介绍最基本的内容,目的只是为了激发您的胃口。更多的例子和案例,看到的文档merge,join以及concat还有链接的功能规格。
基于索引的* -JOIN(+ index-column merges)
设定
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_on和right_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.013135DataFrame.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请注意,我需要指定lsuffix和rsuffix参数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.013135pd.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省略join='inner'是否需要FULL OUTER JOIN(默认):
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有关更多信息,请参见@piRSquared 上pd.concat的此规范帖子。
通用化:merge处理多个DataFrame
通常,将多个DataFrame合并在一起时会出现这种情况。天真的,这可以通过链接merge调用来完成:
df1.merge(df2, ...).merge(df3, ...)但是,对于许多DataFrame,这很快就变得一发不可收拾。此外,可能有必要归纳为未知数量的DataFrame。
在这里,我将介绍pd.concat针对唯一键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。请注意,pd.concat将DataFrames连接到索引。
# 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省略join='inner'完整的外部联接。请注意,您不能指定LEFT或RIGHT 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将DataFrames连接到它们的索引上;merge除非另有说明,否则它在后台进行调用并执行LEFT OUTER JOIN)。
# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
    [df.set_index('key') for df in (B, C)], how='inner').reset_index()
  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0
# join on `key` index
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

![在pd.concat([df0,df1])](https://i.stack.imgur.com/1rb1R.jpg)
