我有一个包含多列的数据框df1。我有df2与相同的列集。我想得到df1中不存在的df1记录。我能够执行以下任务:
df1[~df1['ID'].isin(df2['ID'])]
现在我想进行相同的操作,但是在NAME和ID的组合上。这意味着如果作为df1中的一对的NAME和ID也在df2中作为同一对存在,那么整个记录不应该是我的结果的一部分。
如何使用pandas完成此任务?
答案 0 :(得分:1)
实际上非常简单。
df1[(~df1[['ID', 'Name']].isin(df2[['ID', 'Name']])).any(axis=1)]
您将要比较的列名称作为列表传递。有趣的部分是它输出的内容。
我们说df1
等于:
ID Name
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 1 1
df2
等于:
ID Name
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 1 9
(ID, Name)
和df1
之间的每个df2
对与第9行的匹配。我的回答结果将返回:
ID Name
9 1 1
这正是你想要的。
更详细地说,当你做掩码时:
~df[['ID', 'Name']].isin(df2[['ID', 'Name']]
你明白了:
ID Name
0 False False
1 False False
2 False False
3 False False
4 False False
5 False False
6 False False
7 False False
8 False False
9 False True
我们想要选择其中一列为真的行。为此,我们可以将any(axis=1)
添加到创建的末尾:
0 False
1 False
2 False
3 False
4 False
5 False
6 False
7 False
8 False
9 True
然后当你使用这个系列进行索引时,它只会选择第9行。
答案 1 :(得分:0)
您可以通过连接NAME和ID来创建新列,并使用与您在问题中使用ID相同的新列:
df1['temp'] = df1['NAME'].astype(str)+df1['ID'].astype(str)
df2['temp'] = df2['NAME'].astype(str)+df2['ID'].astype(str)
df1[~df1['temp'].isin(df2['temp'])].drop('temp',1)
答案 2 :(得分:0)
我认为当前接受的答案实际上是正确的。我的印象是,如果该值对也存在于另一个数据框中,则要在df1
中删除一个值对,与它们在各自数据框中所占的行位置无关。< / p>
考虑以下数据框
df1 = pd.DataFrame({'a': list('ABC'), 'b': list('CDF')})
df2 = pd.DataFrame({'a': list('ABAC'), 'b': list('CFFF')})
df1
a b
0 A C
1 B D
2 C F
df2
a b
0 A C
1 B F
2 A F
3 C F
因此,您想删除df1
中的第0行和第2行。但是,根据以上建议,您会得到
df1.isin(df2)
a b
0 True True
1 True False
2 False True
相反,您可以做的是
compare_cols = ['a','b']
mask = pd.Series(list(zip(*[getattr(df1,c) for c in compare_cols]]))).isin(list(zip(*[getattr(df2,c) for c in compare_cols])))
mask
0 True
1 False
2 True
dtype: bool
也就是说,您从要比较的列中构造了一系列元组,这些列来自第一个数据帧,然后检查这些元组是否存在于以相同方式从第二个相应列中获得的元组列表中数据框。
最后一步:df1 = df1.loc[~mask]