Python Pandas:如何根据“OR”条件进行合并?
Posted
技术标签:
【中文标题】Python Pandas:如何根据“OR”条件进行合并?【英文标题】:Python Pandas: How to merge based on an "OR" condition? 【发布时间】:2018-02-02 19:47:06 【问题描述】:假设我有两个数据框,两者的列名是:
table 1 columns:
[ShipNumber, TrackNumber, ShipDate, Quantity, Weight]
table 2 columns:
[ShipNumber, TrackNumber, AmountReceived]
我想根据 ShipNumber 和 TrackNumber 合并这两个表。 但是,如果我只是按以下方式使用合并(伪代码,而不是真实代码):
tab1.merge(tab2, "left", on=['ShipNumber','TrackNumber'])
那么,这意味着两个表中 ShipNumber 和 TrackNumber 列中的值必须匹配。
但是,在我的例子中,有时 ShipNumber 列的值会匹配,有时 TrackNumber 列的值会匹配; 只要两个值之一匹配一行,我希望合并发生。
也就是说,如果 tab 1 中的 row 1 ShipNumber 匹配 tab 2 中的 row 3 ShipNumber,但是两条记录的两个表中的 TrackNumber 不匹配,我仍然想匹配两个表中的两行。
所以基本上这是一个非此即彼的匹配条件(伪代码):
if tab1.ShipNumber == tab2.ShipNumber OR tab1.TrackNumber == tab2.TrackNumber:
then merge
我希望我的问题是有道理的... 非常感谢任何帮助!
按照建议,我查看了这篇文章: Python pandas merge with OR logic 但我认为这不是完全相同的问题,因为该帖子中的 OP 有一个映射文件,因此他们可以简单地进行 2 次合并来解决这个问题。但我没有映射文件,而是有两个具有相同键列的 df(ShipNumber、TrackNumber)
【问题讨论】:
你看到这个帖子了吗:***.com/questions/43925603/… 其实那个帖子并没有解决这里的问题.. 嗨@Vico 我编辑了我的帖子以包含您建议的帖子,但我认为该帖子没有回答我的问题:( 您的输出中总共需要四列吗? IE。A_tab1
, A_tab2
, B_tab1
, B_tab2
?如果只有 A
或 B
需要在任何给定行上匹配,您似乎将需要所有这些。
无论如何,如果没有您的数据或预期的输出,就不能说更多。
【参考方案1】:
使用merge()
和concat()
。然后删除A
和B
匹配的所有重复案例(感谢@Scott Boston 最后一步)。
df1 = pd.DataFrame('A':[3,2,1,4], 'B':[7,8,9,5])
df2 = pd.DataFrame('A':[1,5,6,4], 'B':[4,1,8,5])
df1 df2
A B A B
0 3 7 0 1 4
1 2 8 1 5 1
2 1 9 2 6 8
3 4 5 3 4 5
有了这些数据框,我们应该可以看到:
df1.loc[0]
与 A
匹配 df2.loc[0]
df1.loc[1]
与 B
匹配 df2.loc[2]
df1.loc[3]
在df2.loc[3]
上同时匹配A
和B
我们将使用后缀来跟踪匹配的位置:
suff_A = ['_on_A_match_1', '_on_A_match_2']
suff_B = ['_on_B_match_1', '_on_B_match_2']
df = pd.concat([df1.merge(df2, on='A', suffixes=suff_A),
df1.merge(df2, on='B', suffixes=suff_B)])
A A_on_B_match_1 A_on_B_match_2 B B_on_A_match_1 B_on_A_match_2
0 1.0 NaN NaN NaN 9.0 4.0
1 4.0 NaN NaN NaN 5.0 5.0
0 NaN 2.0 6.0 8.0 NaN NaN
1 NaN 4.0 4.0 5.0 NaN NaN
请注意,第二行和第四行是重复匹配项(对于两个数据帧,A = 4
和 B = 5
)。我们需要删除其中一组。
dups = (df.B_on_A_match_1 == df.B_on_A_match_2) # also could remove A_on_B_match
df.loc[~dups]
A A_on_B_match_1 A_on_B_match_2 B B_on_A_match_1 B_on_A_match_2
0 1.0 NaN NaN NaN 9.0 4.0
0 NaN 2.0 6.0 8.0 NaN NaN
1 NaN 4.0 4.0 5.0 NaN NaN
【讨论】:
我认为您在 concat 之后需要 drop_duplicates 以确保您的消除记录可能在 A 和 B 上都成功加入。 好收获!我将使用示例数据中的边缘情况进行更新。 这种情况下 concat 和 append 是一样的吗? 是的,您也可以使用df1.merge(on='A').append(df1.merge(on='B'))
。我认为concat
通常更快。
@andrew_reece 你能解释一下为什么你的代码中只有一个参数“on”用于合并 df1.merge(on='A').append(df1.merge(on='B' ))?这是什么意思?【参考方案2】:
我会建议这种替代方式来进行这样的合并。这对我来说似乎更容易。
table1["id_to_be_merged"] = table1.apply(
lambda row: row["ShipNumber"] if pd.notnull(row["ShipNumber"]) else row["TrackNumber"], axis=1)
如果需要,您也可以在table2
中添加相同的列,然后根据您的要求在left_in
或right_on
中使用。
【讨论】:
apply 和 lambdas 不适合初学者,因此,由于缺乏解释,答案可能没有那么有用。您还可以使您的代码更具可读性。它在性能上是否超过了上述方法? 我认为这不能解决问题。我认为提问者的大多数行都包括有效的船号和有效的轨道号。此外,提问者不希望将表 1 的船号与表 2 的轨道号相匹配,反之亦然。它必须是(table_1.ShipNumber == table2.ShipNumber) or (table_1.TrackNumber == table2.TrackNumber)
。匹配table_1.ShipNumber == table_2.TrackNumber
会是个问题。以上是关于Python Pandas:如何根据“OR”条件进行合并?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Pandas 或 Python 中根据某些条件放置项目?
如何根据python中的多个条件对excel文件进行重复数据删除?