Эффективное удаление строк из DataFrame, если некоторые значения строк идентичны значениям строк во втором DataFrame - PullRequest
0 голосов
/ 21 ноября 2018
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.remove1 () работает хорошо, смотрите результат ниже, но очень медленно в случае больших наборов данных.

Вот 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

Кто-нибудь знает, как написать более быстрый код и/ или использовать уже существующую функцию?

Ответы [ 3 ]

0 голосов
/ 21 ноября 2018

Метод 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
0 голосов
/ 22 ноября 2018

Может ли 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)]
0 голосов
/ 21 ноября 2018

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'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...