Pandas фильтрация строк в таблице по двум столбцам из другой таблицы

Есть два df "длинный" и "короткий". Нужно отфильтровать строки в длинном df по значениям в коротком. Значения фильтруются по двум столбцам. Решил используя цикл for, но скорость очень низкая: длинна таблицы 80 000 строк, время порядка 8 минут. Фильтрация по str данным, длинна строки до 12 символов. Возможно кто-то подскажет, другие варианты решения. Пытался через map и dict - не получилось.

Условие:

import pandas as pd

# длинный df
columns = ['n1', 'n2']
data = [[1, 5],
        [1, 0],
        [9, 5],
        [1, 1]]

df_long = pd.DataFrame(data=data, columns=columns)
df_long['tr'] = False

# короткий df
columns = ['n1', 'n2']
data = [[1, 5],
        [1, 0],
        [1, 1]]
df_short = pd.DataFrame(data=data, columns=columns)

# вариант решения
# сравниваем наличие n1 и n2, делаем пометку True
# n - номер строки  i, ii - значения
for n, i, ii in zip(range(len(df_long)), df_long['n1'], df_long['n2']):
    if len(df_short.loc[ (df_short['n1']==i) & (df_short['n2']==ii )]) == 1:
        df_long.loc[n, 'tr'] = True

"Длинная"

n1 n2 tr
1 5 False
1 0 False
9 5 False
1 1 False

"Короткая"

n1 n2 None
1 5 None
1 0 None
1 1 None

"Решение"

n1 n2 tr
1 5 True
1 0 True
9 5 False
1 1 True

Ответы (3 шт):

Автор решения: Pak Uula

Вам можно сделать left join - тогда те строки, которые не входят в правую таблицу получат в дополнительных столбцах значение NaN:

import pandas as pd

# длинный df
columns = ['n1', 'n2']
data = [[1, 5],
        [1, 0],
        [9, 5],
        [1, 1]]

df_long = pd.DataFrame(data=data, columns=columns)

# короткий df
columns = ['n1', 'n2']
data = [[1, 5],
        [1, 0],
        [1, 1],
        [2, 1]]
df_short = pd.DataFrame(data=data, columns=columns)
df_short['tr'] = True


nf =  pd.merge(
    left=df_long, 
    right=df_short,
    how='left',
    on=['n1', 'n2'],
)
nf['tr'] = nf['tr'].fillna(value=False)
print(nf)

Обратите внимание, что я перенёс столбец tr в df_short и приравнял значения True: при слиянии таблиц этот столбец будет добавлен в итоговую таблицу, причём для строк, которые во вторую таблицу не входят, там будет значение NaN.

Результат

   n1  n2     tr
0   1   5   True
1   1   0   True
2   9   5  False
3   1   1   True
→ Ссылка
Автор решения: strawdog

~ в виде добавления к ответу @Pak Uula. Колонку tr можно вообще не создавать ни в одном фрейме, а воспользоваться параметром indicator функции merge:

df = pd.merge(df_long, df_short, on=['n1','n2'], how='left', indicator='tr')
df["tr"] = df["tr"]=="both"

df:

    n1  n2  tr
0   1   5   True
1   1   0   True
2   9   5   False
3   1   1   True
→ Ссылка
Автор решения: Angelina

Попробуйте такое решение:

df_long = df_long.query('n1 in @df_short.n1 and n2 in @df_short.n2')

@ — это специальный символ в query(), который позволяет ссылаться на столбцы DataFrame.

Я часто использую данное решение при работе с таблицами и анализе данных. Производительность не страдает.

→ Ссылка