import pandas as pd
df1 = pd.DataFrame({'id': [ 1, 1, 1, 2, 2, 2, 3, 3, 3],
'nr': [91, 92, 93, 91, 92, 93, 91, 92, 93],
'val_a':[22, 23, 24, 33, 34, 35, 44, 43, 42]})
df2 = pd.DataFrame({'id': [ 1, 1, 2, 3, 4, 4, 3, 5],
'nr': [91, 92, 91, 99, 92, 93, 92, 99],
'val_a':[72, 27, 74, 83, 84, 85, 84, 83]})
def eliminate1 ():
for i1, row1 in df1.iterrows():
for i2, row2 in df2.iterrows():
if row1['id'] == row2['id'] and row1['nr'] == row2['nr']:
df1.drop(i1, inplace=True)
df1.reset_index(drop=True, inplace=True)
print(df1)
eliminate1()
我想删除df1中的所有行,其中“ id”和“ nr”在df2的任何行中都具有相等的值。 exclude1()效果很好,请参见下面的结果,但是对于大型数据集而言非常慢。
这是df1和df2:
id nr val_a
0 1 91 22
1 1 92 23
2 1 93 24
3 2 91 33
4 2 92 34
5 2 93 35
6 3 91 44
7 3 92 43
8 3 93 42
id nr val_a
0 1 91 72
1 1 92 27
2 2 91 74
3 3 99 83
4 4 92 84
5 4 93 85
6 3 92 84
7 5 99 83
这里的结果应该像这样:
id nr val_a
0 1 93 24
1 2 92 34
2 2 93 35
3 3 91 44
4 3 93 42
有人知道如何编写更快的代码和/或使用现有功能吗?
答案 0 :(得分:4)
merge
您可以将merge
与indicator=True
一起使用,并仅包括标记为'left_only'
的行。
res = df1.merge(df2.drop('val_a', 1), how='left', on=['id', 'nr'], indicator=True)
res = res.loc[res['_merge'] == 'left_only'].drop('_merge', 1)
print(res)
id nr val_a
2 1 93 24
4 2 92 34
5 2 93 35
6 3 91 44
8 3 93 42
根据'left_only'
,'right_only'
或'both'
,该解决方案可轻松适应任何条件。
答案 1 :(得分:4)
方法1 isin
在将merge
列压缩到tuple
df1[~df1[['id','nr']].apply(tuple,1).isin(df2[['id','nr']].apply(tuple,1))]
Out[43]:
id nr val_a
2 1 93 24
4 2 92 34
5 2 93 35
6 3 91 44
8 3 93 42
方法2 numpy
广播
s1=df1[['id','nr']].values
s2=df2[['id','nr']].values
df1[~np.any(np.all(s1==s2[:,None],-1),0)]
Out[64]:
id nr val_a
2 1 93 24
4 2 92 34
5 2 93 35
6 3 91 44
8 3 93 42
我的方法计时
%timeit df1[~df1[['id','nr']].apply(tuple,1).isin(df2[['id','nr']].apply(tuple,1))]
100 loops, best of 3: 3.67 ms per loop
def m2():
s1 = df1[['id', 'nr']].values
s2 = df2[['id', 'nr']].values
return df1[~np.any(np.all(s1 == s2[:, None], -1), 0)]
%timeit m2()
1000 loops, best of 3: 926 µs per loop
答案 2 :(得分:1)
inner join
是否可以解决您的问题?获取匹配条件的参数索引,然后将其过滤掉。之后,您只需要reset_index()
即可。
df3 = df1.merge(df2, how = 'inner', on = ['id','nr']).reset_index()
id_list = df3['id'].tolist()
df4 = df1[~df1['id'].isin(id_list)]