Определите строки в Pandas фрейме данных, которые уже существуют - PullRequest
1 голос
/ 24 марта 2020

У меня есть два Pandas кадра данных; давайте назовем одну old_df, а другую new_df. Я хочу выделить строки в new_df, которых нет в old_df. Так, например:

import pandas as pd

old_df = pd.DataFrame({'m':[1,2,3,4,5,6],
                       'n':['a','b','c','d','e','f']})

new_df = pd.DataFrame({'m':[2,5,7,8],
                       'n':['b','e','g','h']})

Эти кадры данных выглядят следующим образом:

   m  n
0  1  a
1  2  b
2  3  c
3  4  d
4  5  e
5  6  f

и

   m  n
0  2  b
1  5  e
2  7  g
3  8  h

Я хочу создать маску для new_df, которая указывает, строка уже существует в old_df, что-то вроде:

0    True
1    True
2    False
3    False

Мне удалось объединить столбцы в виде строк в одно строковое значение, чтобы получить две серии Pandas, а затем использовать .isin() на две серии следующим образом:

msk = pd.Series(new_df['m'].astype(str) + new_df['n']).isin(pd.Series(old_df['m'].astype(str) + old_df['n']))

print(msk)

для получения:

0     True
1     True
2    False
3    False
dtype: bool

Это правильный результат, но он слишком уродлив, чтобы быть лучшим ответом. Я думал, что .isin() может также работать на данных, но я не могу заставить это работать.

Есть предложения?

Ответы [ 4 ]

2 голосов
/ 24 марта 2020

Если у вас нет дублированных данных в новом фрейме данных, вы можете объединить их и проверить наличие дубликатов:

(pd.concat([d.assign(is_old=n) for d,n in zip((old_df,new_df), ('old','new'))])
   .assign(from_old=lambda x: x.duplicated(['m','n']))
   .query('is_old=="new"')
)

Вывод:

   m  n is_old  from_old
0  2  b    new      True
1  5  e    new      True
2  7  g    new     False
3  8  h    new     False

Или вы можете использовать merge с indicator=True:

(old_df.merge(new_df, on=['m','n'], how='right', indicator=True)
      .assign(from_old=lambda x: x['_merge']=='both')
)

Выход:

   m  n      _merge  from_old
0  2  b        both      True
1  5  e        both      True
2  7  g  right_only     False
3  8  h  right_only     False
1 голос
/ 24 марта 2020

set

Создание set и проверка содержимого

s = set(zip(*map(old_df.get, new_df)))
mask = [t in s for t in zip(*map(new_df.get, new_df))]
new_df.assign(status=mask)

   m  n  status
0  2  b    True
1  5  e    True
2  7  g   False
3  8  h   False

Некоторые детали

s - это набор всех строк из old_df в виде кортежей. Мы позаботимся о том, чтобы порядок элементов в этих кортежах был таким же, как порядок элементов из new_df

print(s)

{(5, 'e'), (3, 'c'), (4, 'd'), (2, 'b'), (6, 'f'), (1, 'a')}

mask - это понимание списка, которое проверяет каждую строку (как кортеж) ) в new_df и видит, присутствует ли он в нашем наборе s

print(mask)

[True, True, False, False]    
1 голос
/ 24 марта 2020

Вы можете сделать это:

mask = []
for index, row in new_df.iterrows():
    mask.append((old_df == np.array(row)).all(1).any())
print(mask)
1 голос
/ 24 марта 2020

Можно сделать merge и сравнить index:

new_df["status"] = new_df.index.isin(new_df.merge(old_df,on=["m","n"]).index)

print (new_df)

   m  n  status
0  2  b    True
1  5  e    True
2  7  g   False
3  8  h   False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...