Лучший метод Pandas для сравнения двух фреймов данных и поиска записей, которые существуют только в одном

У меня есть DataFrame/электронная таблица, в которой есть столбцы для информации о сотруднике (имя, рабочее место), а также столбцы для общего количества отработанных часов. Моя главная цель — найти сотрудников, которые существуют в одном файле, но не существуют в другом.

Датафрейм ORIGINAL:

 Name      Site    ....other columns
 Anne      A
 Bob       B
 Charlie   A

Датафрейм NEW:

 Name      Site    ....other columns
 Anne      A
 Bob       B
 Doug      B

DataFrame NEW очень похож на ORIGINAL с некоторыми отличиями, и это детали, которые я хочу показать.

  1. Чарли/А был только в ORIGINAL
  2. Дуг/Би был только в NEW

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

Вот код, который у меня есть:

COLS = ['Name','Site'] # Columns to group by to find a 'unique' record

# Records in New, not in Original
df_right = ORIGINAL.merge(NEW.drop_duplicates(), on=COLS, how='right', indicator=True)
df_right = df_right[df_right._merge != 'both'] # Filter out records that exist in both.

# Records in Original, not in New
df_left = ORIGINAL.merge(NEW.drop_duplicates(), on=COLS, how='left', indicator=True)
df_left = df_left[df_left._merge != 'both']

df = pd.concat([df_left,df_right])
# df now contains Name/Site records that exist in one DataFrame but not the other

Есть ли лучший способ выполнить эту проверку вместо того, чтобы делать это дважды и объединять?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
114
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

На самом деле вы можете преобразовать кадры данных в Indexes, а затем просто использовать isin, чтобы проверить, находятся ли целые строки в другом фрейме данных:

cols = ['Name', 'Site']
originalI = pd.Index(ORIGINAL[cols])
newI = pd.Index(NEW[cols])

out = pd.concat([
    ORIGINAL[~originalI.isin(newI)].assign(from_df='ORIGINAL'),
    NEW[~newI.isin(originalI)].assign(from_df='NEW'),    
])

Выход:

>>> out
      Name Site   from_df
2  Charlie    A  ORIGINAL
2     Doug    B       NEW

Если вам нужны только пары «Имя»-«Сайт»; тогда я думаю, что это может сработать:

out = (pd.concat((ORIGINAL[['Name','Site']].assign(From='ORIGINAL'), 
                  NEW[['Name','Site']].assign(From='NEW')))
       .drop_duplicates(subset=['Name', 'Site'], keep=False))

Выход:

      Name Site      From
2  Charlie    A  ORIGINAL
2     Doug    B       NEW

Я хотел специально показать, из какого df он пришел.

Bijan 17.03.2022 00:08

@Bijan обновлен; посмотрите, работает ли он сейчас.

enke 17.03.2022 00:12
Ответ принят как подходящий

Похоже, использование «внешнего» в качестве how было решением

z = pd.merge(ORIGINAL, NEW, on=cols, how = 'outer', indicator=True)
z = z[z._merge != 'both'] # Filter out records from both

Вывод выглядит так (после отображения только тех столбцов, которые меня интересуют)

  Name       Site   _merge
  Charlie    A     left_only
  Doug       B     right_only

Другие вопросы по теме