Pandas左外连接排除法

6

如何在Pandas中进行左外连接,排除交集?

我有两个Pandas数据框:

df1 = pd.DataFrame(data = {'col1' : ['finance', 'finance', 'finance', 'accounting', 'IT'], 'col2' : ['az', 'bh', '', '', '']}) 
df2 = pd.DataFrame(data = {'col1' : ['finance', 'finance', 'finance', 'finance', 'finance'], 'col2' : ['', 'az', '', '', '']})

df1

    col1    col2
0   finance az
1   finance bh
2   finance 
3   accounting  
4   IT  

df2

    col1    col2
0   finance 
1   finance az
2   finance 
3   finance 
4   finance 

正如您所看到的,数据框中也有空值。我尝试使用示例,但它没有给我想要的结果。

common = df1.merge(df2,on=['col1','col2'])
df3=df1[(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))]

我希望输出看起来像这样。
    col1    col2
3   accounting  
4   IT  

你尝试过 common = pd.merge(df1, df2, how='left', on=['col1', 'col2']) 吗? - mrhallak
是的,它给了我与common = df1.merge(df2,on=['col1','col2'])相同的结果。 - StatguyUser
你介意发布一下你当前的输出吗? - mrhallak
3个回答

13

通过将pandas merge的indicator参数设置为True,可以实现Pandas左外连接排除。然后在_merge列中按指示器进行过滤。

df=pd.merge(df1,df2[['col1']],on=['col1'],how="outer",indicator=True)
df=df[df['_merge']=='left_only']
# this following line is just formating
df = df.reset_index()[['col1', 'col2']] 

输出:

col1    col2
0   accounting  
1   IT  

==================================

====以下是一个示例,展示了机制的工作原理。====

df1 = pd.DataFrame({'key1': ['0', '1'],
                     'key2': [-1, -1],
                     'A': ['A0', 'A1'],
                     })


df2 = pd.DataFrame({'key1': ['0', '1'],
                      'key2': [1, -1], 
                    'B': ['B0', 'B1']
                     })

:

:
df1

输出:

    A   key1    key2
0   A0  0       -1
1   A1  1       -1

df2

输出:

    B   key1    key2
0   B0  0       1
1   B1  1       -1

:

df=pd.merge(df1,df2,on=['key1','key2'],how="outer",indicator=True)

输出:

     A  key1    key2    B   _merge
0   A0  0   -1  NaN left_only
1   A1  1   -1  B1  both
2   NaN 0   1   B0  right_only

根据_merge列中的指标,您可以选择一个数据框中存在而另一个数据框中不存在的行。

Translated sentence:

根据_merge列中的指标,您可以选择一个数据框中存在而另一个数据框中不存在的行。

df=df[df['_merge']=='left_only']
df

输出:

    A   key1    key2    B   _merge
0   A0  0   -1  NaN left_only

4
根据Bin的答案,这个问题的一句简短回答可能是:
df=pd.merge(df1,df2[['col1']],on=['col1'],how="outer",indicator=True).query('_merge=="left_only"')

0

这种方法失败是因为你在独立地检查 col1col2 是否匹配,然后将其中一个排除。空字符串会与 finance 行中的空字符串匹配。

你需要:

df3 = df1[(~df1.col1.isin(common.col1))|(~df1.col2.isin(common.col2))]
df3
Out[150]: 
         col1 col2
1     finance   bh
3  accounting     
4          IT  

获取在df2中不存在的df1行。

具体获取:

df3
    col1    col2
3   accounting  
4   IT  

你可以尝试仅选择那些与非匹配的col1

df3 = df1[~df1.col1.isin(df2.col1)]
df3
Out[172]: 
         col1 col2
3  accounting     
4          IT

如果要在col1col2中独立检查匹配项,并在任一列上排除匹配项,同时使NaN不相等/永远不计入匹配项,可以使用以下方法:

df3 = df1[(~df1.col1.isin(common.col1)|df1.col1.isnull())&(~df1.col2.isin(common.col2)|df1.col2.isnull())]
df3
Out[439]: 
         col1 col2
3  accounting  NaN
4          IT  NaN

假设您正在处理实际数据中的实际NaN,即Nonenp.nan,而不是像此示例中的空字符串。如果是后者,您需要添加
df1.replace('', np.nan, inplace=True)
df2.replace('', np.nan, inplace=True)

首先。


不解决问题,对原始问题没有帮助。 - StatguyUser
@Enthusiast 编辑过了,有什么建议? - EFT
它只考虑了一个列col1,而我想要考虑所有的列。 - StatguyUser
@Enthusiast 你能否在这里或者主贴中澄清一下,你想考虑所有列的哪些方面?如果你想要所有不完全匹配的行,那么对于这个两列的情况,你需要我发布的第一个选项,即带有 1 finance bh 行的选项。如果你想要所有与另一个数据框中的任何行都没有共享值的行,则需要使用你最初发布的方法得到的空数据框。你是否想要在始终将空白值视为不相等的情况下执行其中之一?我会稍后进行编辑,但如果没有澄清,这真的是我最后一个猜测你的目标。 - EFT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接