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

假设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

当前回答

如前所述,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())

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

其他回答

这里有另一种解决方法:

df1[~df1.index.isin(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

Or:

df1.loc[df1.index.difference(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

一种方法是在两个dfs中存储一个内部合并表单的结果,然后我们可以简单地选择当一列的值不在这个公共值时的行:

In [119]:

common = df1.merge(df2,on=['col1','col2'])
print(common)
df1[(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))]
   col1  col2
0     1    10
1     2    11
2     3    12
Out[119]:
   col1  col2
3     4    13
4     5    14

EDIT

你已经发现的另一个方法是使用isin,它会生成NaN行,你可以删除:

In [138]:

df1[~df1.isin(df2)].dropna()
Out[138]:
   col1  col2
3     4    13
4     5    14

然而,如果df2不以同样的方式开始行,那么这将不起作用:

df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11, 12,13]})

将产生整个df:

In [140]:

df1[~df1.isin(df2)].dropna()
Out[140]:
   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

我认为那些包含合并的答案是极其缓慢的。因此,我建议另一种方法来获得两个数据框架之间不同的行:

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]})

免责声明:如果您对两个数据框架不同的特定列感兴趣,那么我的解决方案是有效的。如果您只对那些所有列都相等的行感兴趣,则不要使用这种方法。

比方说,col1是一种ID,你只想获取那些不包含在两个数据框架中的行:

ids_in_df2 = df2.col1.unique()
not_found_ids = df[~df['col1'].isin(ids_in_df2 )]

就是这样。你得到的数据框架只包含那些col1在两个数据框架中都不明显的行。

如前所述,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())

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

更容易,更简单,更优雅

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