Pandas: найдите строки, которые не существуют в другом DataFrame несколькими столбцами

то же самое, что и python pandas: как найти строки в одном фрейме данных, но не в другом? но с несколькими столбцами

Это настройка:

import pandas as pd

df = pd.DataFrame(dict(
    col1=[0,1,1,2],
    col2=['a','b','c','b'],
    extra_col=['this','is','just','something']
))

other = pd.DataFrame(dict(
    col1=[1,2],
    col2=['b','c']
))

Теперь я хочу выбрать строки из df, которые не существуют в других. Я хочу сделать выбор col1 и col2

В SQL я бы сделал:

select * from df 
where not exists (
    select * from other o 
    where df.col1 = o.col1 and 
    df.col2 = o.col2
)

И в Pandas я могу сделать что-то подобное, но он чувствует себя очень уродливо. Часть уродства можно было бы избежать, если бы у df был id-column, но он не всегда был доступен.

key_col = ['col1','col2']
df_with_idx = df.reset_index()
common = pd.merge(df_with_idx,other,on=key_col)['index']
mask = df_with_idx['index'].isin(common)

desired_result =  df_with_idx[~mask].drop('index',axis=1)

Итак, может быть, есть более элегантный способ?

Ответ 1

Так как 0.17.0 есть новый indicator параметр, вы можете перейти к merge, который скажет вам, существуют ли строки только в левом, правом или оба:

In [5]:
merged = df.merge(other, how='left', indicator=True)
merged

Out[5]:
   col1 col2  extra_col     _merge
0     0    a       this  left_only
1     1    b         is       both
2     1    c       just  left_only
3     2    b  something  left_only

In [6]:    
merged[merged['_merge']=='left_only']

Out[6]:
   col1 col2  extra_col     _merge
0     0    a       this  left_only
2     1    c       just  left_only
3     2    b  something  left_only

Итак, теперь вы можете фильтровать объединенный df, выбирая только 'left_only' rows

Ответ 2

Интересные

cols = ['col1','col2']
#get copies where the indeces are the columns of interest
df2 = df.set_index(cols)
other2 = other.set_index(cols)
#Look for index overlap, ~
df[~df2.index.isin(other2.index)]

Возврат:

    col1 col2  extra_col
0     0    a       this
2     1    c       just
3     2    b  something

Кажется немного более элегантным...