我有两个熊猫数据帧,它们有一些相同的行。

假设dataframe2是dataframe1的子集。

我怎么能得到dataframe1的行不在dataframe2?

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

df2

   col1  col2
0     1    10
1     2    11
2     3    12

预期结果:

   col1  col2
3     4    13
4     5    14

当前回答

这是最好的方法:

df = df1.drop_duplicates().merge(df2.drop_duplicates(), on=df2.columns.to_list(), 
                   how='left', indicator=True)
df.loc[df._merge=='left_only',df.columns!='_merge']

注意,drop duplicate用于最小化比较。没有他们也可以。最好的方法是比较行内容本身,而不是索引或一/两列,同样的代码也可以用于其他过滤器,如'both'和'right_only',以达到类似的结果。对于这种语法,数据帧可以有任意数量的列,甚至可以有不同的索引。只有列应该出现在两个数据框架中。

为什么这是最好的方法?

索引。差异只适用于基于唯一索引的比较 Pandas.concat()与drop_duplication()结合使用并不理想,因为它还会删除可能只存在于你想保留的数据帧中的行,并出于合理的原因进行复制。

其他回答

更容易,更简单,更优雅

uncommon_indices = np.setdiff1d(df1.index.values, df2.index.values)
new_df = df1.loc[uncommon_indices,:]

这个怎么样:

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 
                               'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 
                               'col2' : [10, 11, 12]})
records_df2 = set([tuple(row) for row in df2.values])
in_df2_mask = np.array([tuple(row) in records_df2 for row in df1.values])
result = df1[~in_df2_mask]

你可以使用isin(dict)方法:

In [74]: df1[~df1.isin(df2.to_dict('l')).all(1)]
Out[74]:
   col1  col2
3     4    13
4     5    14

解释:

In [75]: df2.to_dict('l')
Out[75]: {'col1': [1, 2, 3], 'col2': [10, 11, 12]}

In [76]: df1.isin(df2.to_dict('l'))
Out[76]:
    col1   col2
0   True   True
1   True   True
2   True   True
3  False  False
4  False  False

In [77]: df1.isin(df2.to_dict('l')).all(1)
Out[77]:
0     True
1     True
2     True
3    False
4    False
dtype: bool

如前所述,isin要求列和索引必须相同才能进行匹配。如果match只适用于行内容,一种获取掩码的方法是将行转换为(Multi)Index:

In [77]: df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 'col2' : [10, 11, 12, 13, 14, 10]})
In [78]: df2 = pandas.DataFrame(data = {'col1' : [1, 3, 4], 'col2' : [10, 12, 13]})
In [79]: df1.loc[~df1.set_index(list(df1.columns)).index.isin(df2.set_index(list(df2.columns)).index)]
Out[79]:
   col1  col2
1     2    11
4     5    14
5     3    10

如果需要考虑索引,set_index有关键字参数append来将列追加到现有索引。如果列没有对齐,list(df.columns)可以替换为列规范以对齐数据。

pandas.MultiIndex.from_tuples(df<N>.to_records(index = False).tolist())

也可以用来创建指数,但我怀疑这是否更有效。

有点晚了,但可能值得检查pd.merge的“indicator”参数。

请看另一个问题的例子: 比较PandaS数据框架并返回第一个数据框架中缺少的行