У меня есть 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
с некоторыми отличиями, и это детали, которые я хочу показать.
ORIGINAL
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
Есть ли лучший способ выполнить эту проверку вместо того, чтобы делать это дважды и объединять?
На самом деле вы можете преобразовать кадры данных в Index
es, а затем просто использовать 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
@Bijan обновлен; посмотрите, работает ли он сейчас.
Похоже, использование «внешнего» в качестве 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
Я хотел специально показать, из какого df он пришел.