gpt4 book ai didi

python - Pandas 合并101

转载 作者:太空宇宙 更新时间:2023-11-03 20:00:27 25 4
gpt4 key购买 nike

如何执行与熊猫的(LEFT | RIGHT | FULL)(INNER | OUTER)连接?
合并后如何为缺失的行添加NaN?
合并后如何去除NaN?
我可以合并索引吗?
Cross join with pandas?
如何合并多个DataFrame?
mergejoinconcatupdate?谁?什么?为什么?!


... 和更多。我已经看到这些重复出现的问题,询问有关熊猫合并功能的各个方面。如今,有关合并及其各种用例的大多数信息都分散在数十个措辞不好,无法搜索的帖子中。这里的目的是整理后代的一些更重要的观点。

本QnA旨在成为有关大熊猫习语的一系列有用的用户指南的下一部分(请参阅this post on pivotingthis post on concatenation,我将在稍后进行介绍)。

请注意,本文并非要取代documentation,因此也请阅读!一些示例是从那里获取的。

最佳答案

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

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


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


与不同的列名合并
避免在输出中出现重复的合并键列

在不同条件下与索引合并


有效地使用您的命名索引
合并键作为一个索引,另一个索引

多路合并列和索引(唯一和非唯一)
mergejoin的显着替代品


这篇文章不会讲的内容:


与性能相关的讨论和时间安排(目前)。在适当的地方,最引人注目的是提到更好的替代方案。
处理后缀,删除多余的列,重命名输出以及其他特定用例。还有其他(阅读:更好)的帖子可以解决这个问题,所以请弄清楚!



  注意
  除非另有说明,否则大多数示例在演示各种功能时会默认使用INNER JOIN操作。
  
  此外,此处的所有DataFrame都可以复制和复制,因此
  你可以和他们一起玩。另请参见this post
  关于如何从剪贴板读取DataFrame的信息。
  
  最后,所有JOIN操作的视觉表示都已使用Google绘图进行了手绘。来自here的启示。


足够多的谈话,只告诉我如何使用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
  


要执行INNER JOIN,请在左侧的DataFrame上调用 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


这仅返回来自 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中的键,而 right中缺少的数据将替换为NaN。

同样,对于“正确的外部联接”或“正确的联接”,...



...指定 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。

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

enter image description here

其他联接-左排除,右排除和全排除/ 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具有 keyLeft,并且 right具有 keyRight而不是 key),那么您将必须指定 left_onright_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


避免在输出中重复键列

在合并来自 keyLeftleft和来自 keyRightright时,如果只希望在输出中使用 keyLeftkeyRight(但不能同时使用),则可以将索引设置为初步步骤。

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_onright_on)指定一个列表。

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


或者,如果名称不同,

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


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


合并具有序列索引的DataFrame:请参见 this answer
除了 merge之外,在某些情况下还使用 DataFrame.updateDataFrame.combine_first与另一个更新DataFrame。
pd.merge_ordered是有序JOIN的有用功能。
pd.merge_asof(读取:merge_asOf)对于近似联接很有用。


本节仅介绍最基本的内容,目的只是为了激发您的胃口。有关更多示例和案例,请参见 documentation on merge, join, and concat以及功能说明的链接。



基于索引的* -JOIN(+索引列 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_onright_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


请注意,我需要指定 lsuffixrsuffix参数,因为 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多个数据框

通常,将多个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在其索引上联接DataFrame;它在幕后调用 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

关于python - Pandas 合并101,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59272687/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com