Надежный способ удаления строк в df1, которые также есть в df2 - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть сценарий, в котором у меня есть existing фрейм данных, и у меня есть new фрейм данных, который содержит строки, которые могут быть в фрейме existing, но также могут иметь новые строки. Я изо всех сил пытался найти надежный способ удалить эти существующие строки из new кадра данных, сравнивая его с existing массивом данных.

Я сделал свою домашнюю работу. Решение, похоже, заключается в использовании isin(). Тем не менее, я считаю, что это скрытые опасности. В частности:

панды получают строки, которые НЕ находятся в другом фрейме данных

Панды не могут вычислить isin с дублирующейся осью

Pandas поддерживает int для float при фильтрации

Есть ли способ надежно отфильтровать строки из одного кадра данных на основе членства / содержания в другом кадре данных? Простой пример использования, который не захватывает угловые случаи, показан ниже. Обратите внимание, что я хочу удалить строки в new, которые находятся в existing, чтобы new содержал только строки, не входящие в existing. Более простая проблема обновления existing новыми строками от new может быть достигнута с помощью pd.merge() + DataFrame.drop_duplicates()

In [53]: df1 = pd.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]})  
    ...: df2 = pd.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})                                                                                             

In [54]: df1                                                                                                                                                                
Out[54]: 
   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

In [55]: df2                                                                                                                                                                
Out[55]: 
   col1  col2
0     1    10
1     2    11
2     3    12

In [56]: df1[~df1.isin(df2)]                                                                                                                                                
Out[56]: 
   col1  col2
0   NaN   NaN
1   NaN   NaN
2   NaN   NaN
3   4.0  13.0
4   5.0  14.0

In [57]: df1[~df1.isin(df2)].dropna()                                                                                                                                       
Out[57]: 
   col1  col2
3   4.0  13.0
4   5.0  14.0

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

Мы можем использовать DataFrame.merge с indicator = True + DataFrame.query и DataFrame.drop

df_filtered=( df1.merge(df2,how='outer',indicator=True)
                 .query("_merge == 'left_only'")
                 .drop('_merge',axis=1) )
print(df_filtered)

   col1  col2
3     4    13
4     5    14

если теперь, например, мы изменим значение строки 0:

df1.iat[0,0]=3

строка 0 больше не фильтруется

df_filtered=( df1.merge(df2,how='outer',indicator=True)
                 .query("_merge == 'left_only'")
                 .drop('_merge',axis=1) )
print(df_filtered)

   col1  col2
0     3    10
3     4    13
4     5    14

Шаг за шагом

df_filtered=( df1.merge(df2,how='outer',indicator=True)
 )
print(df_filtered)
   col1  col2      _merge
0     3    10   left_only
1     2    11        both
2     3    12        both
3     4    13   left_only
4     5    14   left_only
5     1    10  right_only

df_filtered=( df1.merge(df2,how='outer',indicator=True).query("_merge == 'left_only'")
 )
print(df_filtered)
   col1  col2     _merge
0     3    10  left_only
3     4    13  left_only
4     5    14  left_only

df_filtered=( df1.merge(df2,how='outer',indicator=True)
                 .query("_merge == 'left_only'")
                 .drop('_merge',axis=1)
 )
print(df_filtered)
   col1  col2
0     3    10
3     4    13
4     5    14
0 голосов
/ 01 ноября 2019

Вы можете попробовать серию isin. Это не зависит от index. Т.е., он проверяет только значения. Вам просто нужно преобразовать столбцы каждого кадра данных в серию кортежей, чтобы создать маску

s1 = df1.agg(tuple, axis=1)
s2 = df2.agg(tuple, axis=1)

df1[~s1.isin(s2)]

Out[538]:
   col1  col2
3     4    13
4     5    14
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...