У меня есть два фрейма данных df1 и df2, где df2 - это подмножество df1. Как мне получить новый фрейм данных (df3), который является разницей между двумя фреймами данных?
Другими словами, фрейм данных, в котором есть все строки / столбцы в df1, которых нет в df2?
Ответы:
Используя
drop_duplicates
pd.concat([df1,df2]).drop_duplicates(keep=False)
Update :
df1=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]}) df2=pd.DataFrame({'A':[1],'B':[2]})
Он будет выводиться, как показано ниже, что неверно
pd.concat([df1, df2]).drop_duplicates(keep=False) Out[655]: A B 1 2 3
Out[656]: A B 1 2 3 2 3 4 3 3 4
Метод 1: Использование
isin
сtuple
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))] Out[657]: A B 1 2 3 2 3 4 3 3 4
Способ 2:
merge
сindicator
df1.merge(df2,indicator = True, how='left').loc[lambda x : x['_merge']!='both'] Out[421]: A B _merge 1 2 3 left_only 2 3 4 left_only 3 3 4 left_only
источник
pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
float
(потому что12.00000000001 != 12
). Лучше всего найти заданное пересечение идентификаторов в двух фреймах данных и получить разницу на основе этого.indicator=True
) - очень универсальный и полезный инструмент, я бы хотел видеть его в верхней части этого ответа, но с «внешним», а не «левым» соединением, чтобы охватить все 3 ситуации.Для строк попробуйте следующее, где
Name
находится столбец объединенного индекса (может быть список для нескольких общих столбцов или указатьleft_on
иright_on
):m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)
Этот
indicator=True
параметр полезен, поскольку он добавляет столбец с именем_merge
, в котором все изменения междуdf1
иdf2
, разделены на 3 возможных типа: «left_only», «right_only» или «оба».Для столбцов попробуйте следующее:
источник
merge
withindicator=True
- классическое решение для сравнения фреймов данных по заданным полям.Принимается ответ Метод 1 не будет работать для кадров данных с Nans внутри, как
pd.np.nan != pd.np.nan
. Я не уверен, что это лучший способ, но его можно избежать,df1[~df1.astype(str).apply(tuple, 1).isin(df2.astype(str).apply(tuple, 1))]
источник
edit2, я нашел новое решение без необходимости установки индекса
newdf=pd.concat[df1,df2].drop_duplicates(keep=False)
Хорошо, я обнаружил, что ответ самого высокого голоса уже содержит то, что я выяснил. Да, мы можем использовать этот код только при условии, что в каждых двух dfs нет дубликатов.
У меня есть хитрый метод. Сначала мы устанавливаем 'Name' как индекс двух фреймов данных, заданных вопросом. Поскольку у нас одинаковое 'Name' в двух dfs, мы можем просто удалить индекс 'меньшего' df из 'большего' df . Вот код.
df1.set_index('Name',inplace=True) df2.set_index('Name',inplace=True) newdf=df1.drop(df2.index)
источник
import pandas as pd # given df1 = pd.DataFrame({'Name':['John','Mike','Smith','Wale','Marry','Tom','Menda','Bolt','Yuswa',], 'Age':[23,45,12,34,27,44,28,39,40]}) df2 = pd.DataFrame({'Name':['John','Smith','Wale','Tom','Menda','Yuswa',], 'Age':[23,12,34,44,28,40]}) # find elements in df1 that are not in df2 df_1notin2 = df1[~(df1['Name'].isin(df2['Name']) & df1['Age'].isin(df2['Age']))].reset_index(drop=True) # output: print('df1\n', df1) print('df2\n', df2) print('df_1notin2\n', df_1notin2) # df1 # Age Name # 0 23 John # 1 45 Mike # 2 12 Smith # 3 34 Wale # 4 27 Marry # 5 44 Tom # 6 28 Menda # 7 39 Bolt # 8 40 Yuswa # df2 # Age Name # 0 23 John # 1 12 Smith # 2 34 Wale # 3 44 Tom # 4 28 Menda # 5 40 Yuswa # df_1notin2 # Age Name # 0 45 Mike # 1 27 Marry # 2 39 Bolt
источник
Возможно, более простой однострочник с одинаковыми или разными именами столбцов. Работало, даже когда df2 ['Name2'] содержал повторяющиеся значения.
newDf = df1.set_index('Name1') .drop(df2['Name2'], errors='ignore') .reset_index(drop=False)
источник
Небольшая вариация решения nice @ liangli, которая не требует изменения индекса существующих фреймов данных:
newdf = df1.drop(df1.join(df2.set_index('Name').index))
источник
Поиск отличий по индексу. Предполагая, что df1 является подмножеством df2 и индексы переносятся при подмножестве
df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna() # Example df1 = pd.DataFrame({"gender":np.random.choice(['m','f'],size=5), "subject":np.random.choice(["bio","phy","chem"],size=5)}, index = [1,2,3,4,5]) df2 = df1.loc[[1,3,5]] df1 gender subject 1 f bio 2 m chem 3 f phy 4 m bio 5 f bio df2 gender subject 1 f bio 3 f phy 5 f bio df3 = df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna() df3 gender subject 2 m chem 4 m bio
источник
В дополнение к принятому ответу я хотел бы предложить еще одно более широкое решение, которое может найти различие двухмерных наборов двух кадров данных с любым
index
/columns
(они могут не совпадать для обоих данных). Также метод позволяет установить допуск дляfloat
элементов для сравнения фреймов данных (он используетnp.isclose
)import numpy as np import pandas as pd def get_dataframe_setdiff2d(df_new: pd.DataFrame, df_old: pd.DataFrame, rtol=1e-03, atol=1e-05) -> pd.DataFrame: """Returns set difference of two pandas DataFrames""" union_index = np.union1d(df_new.index, df_old.index) union_columns = np.union1d(df_new.columns, df_old.columns) new = df_new.reindex(index=union_index, columns=union_columns) old = df_old.reindex(index=union_index, columns=union_columns) mask_diff = ~np.isclose(new, old, rtol, atol) df_bool = pd.DataFrame(mask_diff, union_index, union_columns) df_diff = pd.concat([new[df_bool].stack(), old[df_bool].stack()], axis=1) df_diff.columns = ["New", "Old"] return df_diff
Пример:
In [1] df1 = pd.DataFrame({'A':[2,1,2],'C':[2,1,2]}) df2 = pd.DataFrame({'A':[1,1],'B':[1,1]}) print("df1:\n", df1, "\n") print("df2:\n", df2, "\n") diff = get_dataframe_setdiff2d(df1, df2) print("diff:\n", diff, "\n")
Out [1] df1: A C 0 2 2 1 1 1 2 2 2 df2: A B 0 1 1 1 1 1 diff: New Old 0 A 2.0 1.0 B NaN 1.0 C 2.0 NaN 1 B NaN 1.0 C 1.0 NaN 2 A 2.0 NaN C 2.0 NaN
источник
Как упоминалось здесь ,
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
правильное решение, но оно даст неправильный результат, если
df1=pd.DataFrame({'A':[1],'B':[2]}) df2=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
В этом случае вышеупомянутое решение предоставит пустой фрейм данных , вместо этого вы должны использовать
concat
метод после удаления дубликатов из каждого фрейма данных.Использовать
concate with drop_duplicates
df1=df1.drop_duplicates(keep="first") df2=df2.drop_duplicates(keep="first") pd.concat([df1,df2]).drop_duplicates(keep=False)
источник