反加入熊猫

时间:2016-07-22 01:05:12

标签: python pandas dataframe merge anti-join

我有两个表,我想附加它们,以便只保留表A中的所有数据,并且只有在表B的数据唯一时才添加来自表B的数据(键值在表A和B中是唯一的但是在在某些情况下,密钥将出现在表A和表B中。

我认为执行此操作的方法将涉及某种过滤连接(反连接)以获取表B中未在表A中出现的值,然后附加两个表。

我熟悉R,这是我在R中用来做这个的代码。

library("dplyr")

## Filtering join to remove values already in "TableA" from "TableB"
FilteredTableB <- anti_join(TableB,TableA, by = "Key")

## Append "FilteredTableB" to "TableA"
CombinedTable <- bind_rows(TableA,FilteredTableB)

我如何在python中实现这一目标?

6 个答案:

答案 0 :(得分:13)

考虑以下数据框

TableA = pd.DataFrame(np.random.rand(4, 3),
                      pd.Index(list('abcd'), name='Key'),
                      ['A', 'B', 'C']).reset_index()
TableB = pd.DataFrame(np.random.rand(4, 3),
                      pd.Index(list('aecf'), name='Key'),
                      ['A', 'B', 'C']).reset_index()
TableA

enter image description here

TableB

enter image description here

这是做你想做的事的一种方式

方法1

# Identify what values are in TableB and not in TableA
key_diff = set(TableB.Key).difference(TableA.Key)
where_diff = TableB.Key.isin(key_diff)

# Slice TableB accordingly and append to TableA
TableA.append(TableB[where_diff], ignore_index=True)

enter image description here

方法2

rows = []
for i, row in TableB.iterrows():
    if row.Key not in TableA.Key.values:
        rows.append(row)

pd.concat([TableA.T] + rows, axis=1).T

时序

4行,重叠2次

方法1更快

enter image description here

10,000行5,000重叠

循环不好

enter image description here

答案 1 :(得分:5)

我遇到了同样的问题。 This answer使用how='outer'indicator=True merge激励我提出这个解决方案:

import pandas as pd
import numpy as np

TableA = pd.DataFrame(np.random.rand(4, 3),
                      pd.Index(list('abcd'), name='Key'),
                      ['A', 'B', 'C']).reset_index()
TableB = pd.DataFrame(np.random.rand(4, 3),
                      pd.Index(list('aecf'), name='Key'),
                      ['A', 'B', 'C']).reset_index()

print('TableA', TableA, sep='\n')
print('TableB', TableB, sep='\n')

TableB_only = pd.merge(
    TableA, TableB,
    how='outer', on='Key', indicator=True, suffixes=('_foo','')).query(
        '_merge == "right_only"')

print('TableB_only', TableB_only, sep='\n')

Table_concatenated = pd.concat((TableA, TableB_only), join='inner')

print('Table_concatenated', Table_concatenated, sep='\n')

打印此输出:

TableA
  Key         A         B         C
0   a  0.035548  0.344711  0.860918
1   b  0.640194  0.212250  0.277359
2   c  0.592234  0.113492  0.037444
3   d  0.112271  0.205245  0.227157
TableB
  Key         A         B         C
0   a  0.754538  0.692902  0.537704
1   e  0.499092  0.864145  0.004559
2   c  0.082087  0.682573  0.421654
3   f  0.768914  0.281617  0.924693
TableB_only
  Key  A_foo  B_foo  C_foo         A         B         C      _merge
4   e    NaN    NaN    NaN  0.499092  0.864145  0.004559  right_only
5   f    NaN    NaN    NaN  0.768914  0.281617  0.924693  right_only
Table_concatenated
  Key         A         B         C
0   a  0.035548  0.344711  0.860918
1   b  0.640194  0.212250  0.277359
2   c  0.592234  0.113492  0.037444
3   d  0.112271  0.205245  0.227157
4   e  0.499092  0.864145  0.004559
5   f  0.768914  0.281617  0.924693

答案 2 :(得分:2)

可以想象的最简单答案:

tableB = pd.concat([tableB, pd.Series(1)], axis=1)
mergedTable = tableA.merge(tableB, how="left" on="key")

answer = mergedTable[mergedTable.iloc[:,-1].isnull()][tableA.columns.tolist()]

也应该是最快提出的。

答案 3 :(得分:2)

indicator = True命令中的

merge通过创建具有三个可能值的新列_merge来告诉您应用了哪个联接:

  • left_only
  • right_only
  • both

您需要使用right_only并将其附加回第一张表。就是这样。

使用后,请不要忘记删除_merge列。

outer_join = TableA.merge(TableB, how = 'outer', indicator = True)

anti_join_B_only = outer_join[outer_join._merge == 'right_only']

anti_join_B_only = anti_join_B_only.drop('_merge', axis = 1)

combined_table = TableA.merge(anti_join_B_only, how = 'outer')

容易!

答案 4 :(得分:1)

您将同时拥有表TableATableB,以便DataFrame个对象在各自的表中具有唯一值的列,但某些列可能具有同时发生的值(具有两个表中的行数相同)。

然后,我们要将TableA中的行与TableB中与'{1}}中的任何行匹配的行与'Key'列合并。这个概念是将它描述为比较两个系列的可变长度,并将TableA中的行与sA的{​​{1}}值相匹配sB }}的。以下代码解决了这个练习:

sB

请注意,这也会影响sA的数据。您可以使用import pandas as pd TableA = pd.DataFrame([[2, 3, 4], [5, 6, 7], [8, 9, 10]]) TableB = pd.DataFrame([[1, 3, 4], [5, 7, 8], [9, 10, 0]]) removeTheseIndexes = [] keyColumnA = TableA.iloc[:,1] # your 'Key' column here keyColumnB = TableB.iloc[:,1] # same for i in range(0, len(keyColumnA)): firstValue = keyColumnA[i] for j in range(0, len(keyColumnB)): copycat = keyColumnB[j] if firstValue == copycat: removeTheseIndexes.append(j) TableB.drop(removeTheseIndexes, inplace = True) TableA = TableA.append(TableB) TableA = TableA.reset_index(drop=True) 并将其重新分配给TableB,然后再inplace=False

newTable

答案 5 :(得分:0)

根据其他建议之一,下面是一个应做的功能。仅使用熊猫函数,没有循环。您也可以使用多列作为键。如果将行output = merged.loc[merged.dummy_col.isna(),tableA.columns.tolist()] 更改为output = merged.loc[~merged.dummy_col.isna(),tableA.columns.tolist()] ,则将具有semi_join。

def anti_join(tableA,tableB,on):

   #if joining on index, make it into a column
   if tableB.index.name is not None:
       dummy = tableB.reset_index()[on]
   else:
       dummy = tableB[on]

   #create a dummy columns of 1s
   if isinstance(dummy, pd.Series):
       dummy = dummy.to_frame()

   dummy.loc[:,'dummy_col'] = 1

   #preserve the index of tableA if it has one
   if tableA.index.name is not None:
       idx_name = tableA.index.name
       tableA = tableA.reset_index(drop = False)
   else:
       idx_name = None

   #do a left-join
   merged = tableA.merge(dummy,on=on,how='left')

   #keep only the non-matches
   output = merged.loc[merged.dummy_col.isna(),tableA.columns.tolist()]

   #reset the index (if applicable)
   if idx_name is not None:
       output = output.set_index(idx_name)

   return(output)