这篇文章旨在为读者提供有关使用 Pandas 进行 SQL 风格合并的入门知识、如何使用它以及何时不使用它。
具体来说,本文将讨论以下内容:
-
p2
- merging with different column names
- merging with multiple columns
- avoiding duplicate merge key column in output
本帖(以及我在这个主题下发布的其他帖子)不会涉及以下内容:
-
与性能相关的讨论和时间安排(目前)。在适当的情况下,主要提到了更好的替代方案。
-
处理后缀、删除多余的列、重命名输出和其他特定用例。还有其他(阅读:更好的)帖子处理这些,所以弄清楚吧!
注意: 除非另有说明,大多数示例在演示各种功能时默认采用 INNER JOIN 操作。
此外,这里的所有 DataFrames 都可以复制和复制,因此您可以使用它们。此外,请参阅 此帖子 ,了解如何从剪贴板读取 DataFrames。
最后,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
为了简单起见,键列具有相同的名称(目前)。
表示 INNER JOIN 为
注意 :本图表以及接下来的图表均遵循以下惯例:
-
蓝色 表示合并结果中存在的行
-
红色 表示从结果中排除的行(即删除)
-
绿色 结果中用 s
NaN
替换的缺失值
要执行 INNER JOIN,请 merge
,并指定右侧 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
共享公共键的行(在此示例中为 \'B\' 和 \'D) right
。
或 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
中的键 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 插入到两个框架中以表示缺失的行。
文档很好地总结了这些不同的合并:
其他 JOIN - LEFT-Exclusion、RIGHT-Exclusion 和 FULL-Exclusion/ANTI JOIN
如果需要 LEFT-Exclusion JOIN 和 RIGHT-Exclusion JOIN, 则分两个步骤。
对于 LEFT-Exclusive JOIN,表示为
首先执行 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
类似地,对于 RIGHT-Exclusive 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
最后,如果您需要执行仅保留左侧或右侧键但不同时保留两者的合并(换句话说,执行 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 keyLeft
和 right
has 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
避免输出中出现重复的键列
当根据 keyLeft
来自 left
和 keyRight
来自 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 操作时可能很重要。
仅合并某个 DataFrame 中的一列
例如,考虑
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
如果您只需要合并“newcol”(不合并任何其他列),通常可以在合并之前对列进行子集处理:
left.merge(right3[['key', 'newcol']], on='key')
key value newcol
0 B 0.400157 0
1 D 2.240893 1
如果您正在执行 LEFT OUTER JOIN,那么更高性能的解决方案将涉及 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 、 join 和 concat 的文档以及函数规范的链接。
继续阅读
跳转到 Pandas Merging 101 中的其他主题继续学习:
*您在这里。