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?如果只有 AB 需要在任何给定行上匹配,您似乎将需要所有这些。 无论如何,如果没有您的数据或预期的输出,就不能说更多。 【参考方案1】:

使用merge()concat()。然后删除AB 匹配的所有重复案例(感谢@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] 上同时匹配AB

我们将使用后缀来跟踪匹配的位置:

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 = 4B = 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_inright_on 中使用。

【讨论】:

applylambdas 不适合初学者,因此,由于缺乏解释,答案可能没有那么有用。您还可以使您的代码更具可读性。它在性能上是否超过了上述方法? 我认为这不能解决问题。我认为提问者的大多数行都包括有效的船号和有效的轨道号。此外,提问者不希望将表 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 pandas 中的条件拆分列

如何根据python中的多个条件对excel文件进​​行重复数据删除?

如何使用 python 或 pandas 根据包含字典列表的列过滤 DataFrame?

如何在 python Pandas 中执行/解决条件连接?

根据 Pandas DF 中每行的条件获取列标题列表