如何根据其在另一个df中存在的列值从数据框中删除行?

时间:2013-12-19 09:34:52

标签: pandas

给定两个数据帧A和B,它们都有列'x','y'我怎么能有效地删除A中的所有行,它们的对(x,y)出现在B中。

我考虑过在A上使用行迭代器实现它,然后每对检查它是否存在于B中,但我猜这是效率最低的方式......

我尝试使用Filter dataframe rows if value in column is in a set list of values中建议的.isin函数,但无法将其用于多列。

示例数据框:

A = pd.DataFrame([[1, 2], [1, 4], [3, 4], [2, 4]], columns=['x', 'y'])
B = pd.DataFrame([[1, 2], [3, 4]], columns=['x', 'y'])

操作后C应包含[1,4]和[2,4]。

3 个答案:

答案 0 :(得分:4)

在pandas master(或将来的0.13)isin也会接受DataFrames,但问题是它只是查看每列中的值,而不是列的精确行组合。

取自@AndyHayden的评论(https://github.com/pydata/pandas/issues/4421#issuecomment-23052472),采用类似的方法:

In [3]: mask = pd.Series(map(set(B.itertuples(index=False)).__contains__, A.itertuples(index=False)))
In [4]: A[~mask]
Out[4]:
   x  y
1  1  4
3  2  4

或者更易阅读的版本:

set_B = set(B.itertuples(index=False))
mask = [x not in set_B for x in A.itertuples(index=False)]

与@ Acorbe的答案相比,这可能带来的好处是保留了A的索引,并且不会删除A中的重复行(但这取决于您当然想要的内容)。< / p>


正如我所说,0.13将接受DataFrame到isin。但是,我不认为这会解决这个问题,因为索引也必须相同:

In [27]: A.isin(B)
Out[27]:
       x      y
0   True   True
1  False   True
2  False  False
3  False  False

您可以通过将其转换为dict来解决此问题,但现在它不会查看两列的组合,而是仅针对每个列:

In [28]: A.isin(B.to_dict(outtype='list'))
Out[28]:
       x     y
0   True  True
1   True  True
2   True  True
3  False  True

答案 1 :(得分:3)

对于那些寻找单栏解决方案的人:

new_df = df1[~df1["column_name"].isin(df2["column_name"])]

〜是NOT的逻辑运算符。

因此,当在df2 [“column_name”]中找不到df1 [“column_name”]的值时,这将创建一个新的数据帧

答案 2 :(得分:0)

一种选择是生成两个sets,例如A_setB_set,其元素是DataFrames的行。因此,可以使用快速设置差异操作A_set - B_set

 A_set = set(map(tuple,A.values))   #we need to have an hashable object before generating a set
 B_set = set(map(tuple,B.values))  

 C_set = A_set - B_set 
 C_set
    {(1, 4), (2, 4)}

 C = pd.DataFrame([c for c in C_set], columns=['x','y'])  

        x  y
     0  2  4
     1  1  4

此程序涉及一些初步转换操作。