LEFT
| RIGHT
| FULL
)(INNER
| OUTER
)联接?merge
? join
? concat
? update
?谁?什么?为什么?!...等等。我已经看到这些重复出现的问题,询问有关熊猫合并功能的各个方面。如今,有关合并及其各种用例的大多数信息都分散在数十个措辞不好,无法搜索的帖子中。这里的目的是整理一些关于后代的更重要的观点。
此QnA旨在作为一系列有关常见熊猫习语的有用用户指南的下一部分(请参阅this post on pivoting和this post on concatenation,我将在稍后进行介绍)。
请注意,该帖子不是 ,它是documentation的替代内容,因此也请阅读!一些示例是从那里获取的。
答案 0 :(得分:221)
这篇文章旨在为读者提供有关SQL风格与熊猫的合并,使用方法以及何时不使用它的入门知识。
特别是,这是这篇文章的内容:
基本知识-联接类型(左,右,外,内)
merge
和join
的显着替代方式该帖子不会涉及的内容:
注意
除非另有说明,否则大多数示例在演示各种功能时都会默认使用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
DataFrameB
中join列的键 引用right
DataFrame中join列中的键,并且相交 代表left
和right
共同的键。 阴影区域表示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
这仅返回left
和right
中共享同一密钥(在此示例中为“ 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。
文档很好地总结了这些各种合并:
如果您需要分两个步骤不包含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_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操作时,这可能很重要。
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*
操作和功能 在某些情况下,除了merge
,DataFrame.update
和DataFrame.combine_first
之外,还用于更新一个DataFrame。
pd.merge_ordered
是有序JOIN的有用功能。
pd.merge_asof
(阅读:merge_asOf)对于近似联接很有用。
本节仅介绍最基本的知识,目的只是为了激发您的胃口。有关更多示例和案例,请参见documentation on merge
, join
, and concat
以及功能说明的链接。
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_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.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
请注意,我需要指定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.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)
答案 2 :(得分:5)
在这个答案中,我将考虑pandas.concat
的实际示例。
请考虑以下具有相同列名的DataFrames
:
Preco2018 ,大小为(8784,5)
Preco 2019 ,大小为(8760,5)
具有相同的列名。
您可以使用pandas.concat
简单地组合它们
import pandas as pd
frames = [Preco2018, Preco2019]
df_merged = pd.concat(frames)
这会导致以下尺寸的DataFrame(17544,5)
如果您想可视化,它最终会像这样
(Source)
答案 3 :(得分:0)
本文将涉及以下主题:
merge
在这里有缺点)通常,将多个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)
本文将涉及以下主题:
merge
,join
,concat
有一些选项,根据用途,某些选项比其他选项更简单 情况。
DataFrame.merge
与left_index
和right_index
(或left_on
和right_on
使用名称索引)
- 支持内部/左/右/全
- 一次只能加入两个
- 支持列-列,索引-列,索引-索引联接
DataFrame.join
(加入索引)
- 支持内部/左侧(默认)/右侧/完整
- 可以一次加入多个DataFrames
- 支持索引-索引连接
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
其他联接遵循类似的语法。
重要的选择
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.013135
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.merge
和left_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
才能执行索引到列的联接。您可以在多列上联接,前提是左侧的索引级别数目等于右侧的列数目。
merge
和join
无法混合合并。您需要使用DataFrame.set_index
将索引设置为先行步骤。
如果您的索引是命名的,那么从熊猫> = 0.23开始,concat
允许您将索引名称指定为DataFrame.merge
(或根据需要指定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_on
跳至“熊猫合并101”中的其他主题以继续学习:
*您在这里