python - 熊猫合并101
问题描述
- 如何使用熊猫执行 (
INNER
| (LEFT
|RIGHT
|FULL
)OUTER
) ?JOIN
- 如何在合并后为缺失的行添加 NaN?
- 合并后如何摆脱 NaN?
- 我可以合并索引吗?
- 如何合并多个 DataFrame?
- 与熊猫交叉加入
merge
?join
?concat
?update
? 谁?什么?为什么?!
... 和更多。我已经看到这些反复出现的问题询问熊猫合并功能的各个方面。今天,关于合并及其各种用例的大部分信息都分散在数十个措辞不当、无法搜索的帖子中。这里的目的是为后代整理一些更重要的观点。
本问答旨在成为有关常见 pandas 习语的一系列有用用户指南的下一部分(请参阅这篇关于 pivoting的文章和关于 concatenation 的这篇文章,我稍后会谈到)。
请注意,这篇文章并不是要替代文档,所以也请阅读!一些例子取自那里。
目录
为了方便访问。
合并基础 - 连接的基本类型(首先阅读此内容)
解决方案
这篇文章旨在为读者提供 SQL 风格与 Pandas 合并的入门知识,如何使用它以及何时不使用它。
特别是,本文将介绍以下内容:
基础 - 连接类型(左、右、外、内)
- 合并不同的列名
- 与多列合并
- 避免输出中出现重复的合并键列
这篇文章(以及我在这个线程上的其他帖子)不会经过:
- 与性能相关的讨论和时间安排(目前)。在适当的情况下,主要提到了更好的替代方案。
- 处理后缀、删除额外列、重命名输出和其他特定用例。还有其他(阅读:更好的)帖子可以解决这个问题,所以弄清楚吧!
注意 大多数示例在演示各种功能时默认为 INNER JOIN 操作,除非另有说明。
此外,这里的所有 DataFrame 都可以复制和复制,以便您可以使用它们。此外,请参阅这篇 关于如何从剪贴板读取 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表示为
注意 这一点,以及即将到来的数字都遵循这个约定:
- 蓝色表示合并结果中存在的行
- 红色表示从结果中排除的行(即,已删除)
- 绿色表示
NaN
在结果中用 s替换的缺失值
要执行 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
这仅返回共享公共键的行(在此示例中为“B”和“D”)left
。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-Excluding、RIGHT-Excluding 和 FULL-Excluding/ANTI JOIN
如果您需要LEFT-Excluding JOIN和RIGHT-Excluding JOIN分两步。
对于 LEFT-Excluding 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-Excluding 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),
你可以用类似的方式做到这一点——</p>
(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
haskeyLeft
和right
haskeyRight
而不是key
——那么您将必须指定left_on
andright_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
fromleft
和keyRight
fromright
时,如果您只需要输出中的一个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
如果您正在执行 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*
的操作和功能
将 DataFrame 与索引上的 Series 合并:请参阅此答案。
此外
merge
,DataFrame.update
和DataFrame.combine_first
在某些情况下还用于用另一个 DataFrame 更新一个 DataFrame。pd.merge_ordered
是有序 JOIN 的有用函数。pd.merge_asof
(阅读:merge_asOf)对于近似连接很有用。
本节仅涵盖最基本的内容,旨在激发您的胃口。有关更多示例和案例,请参阅有关 、 和 的文档以及函数merge
join
concat
规范的链接。
继续阅读
跳转到 Pandas Merging 101 中的其他主题继续学习:
*你在这里。
推荐阅读
- jquery - google.maps.event.addDomListener 在第二次重新加载后无法与 Firefox 一起使用
- react-native - Card标签里面的text标签是并排写的,如何让每个Text标签单独一行?
- javascript - 事件触发后全局变量仍未初始化?
- javascript - mapStateToProps 赋值的最佳实践
- python - Flask-SQLAlchemy 摆脱 `idle in transaction`
- regex - 正则表达式:删除带有行继续字符的多个结尾
- php - 错误:在属性路径“provincie_id”处给出的“int”、“App\Entity\Provincie”类型的预期参数
- azure - 在 Azure 中,如何正确抑制电子邮件警报?
- java - 如何使用可以使用方法的 ArrayList 创建动态对象?
- r - ui 和服务器脚本作为一个脚本运行,运行良好。但是在不同的文件 ui.R 和 server.R 中运行脚本会引发错误