У меня есть два фрейма данных. Примеры:
df1:
Date Fruit Num Color
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 8.6 Orange
2013-11-24 Apple 7.6 Green
2013-11-24 Celery 10.2 Green
df2:
Date Fruit Num Color
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 8.6 Orange
2013-11-24 Apple 7.6 Green
2013-11-24 Celery 10.2 Green
2013-11-25 Apple 22.1 Red
2013-11-25 Orange 8.6 Orange
Каждый фрейм данных имеет дату в качестве индекса. Оба фрейма данных имеют одинаковую структуру.
Что я хочу сделать, так это сравнить эти два фрейма данных и найти, какие строки находятся в df2, а какие нет в df1. Я хочу сравнить дату (индекс) и первый столбец (Banana, APple и т.д.), чтобы узнать, существуют ли они в df2 vs df1.
Я пробовал следующее:
- Вывод разницы в двух фреймах данных Pandas бок о бок - подчеркивая разницу
- Сравнение двух фреймов данных pandas на предмет различий
Для первого подхода я получаю эту ошибку: «Исключение: можно сравнивать только объекты DataFrame с одинаковой меткой» . Я попытался удалить дату как индекс, но получил ту же ошибку.
При третьем подходе я получаю assert для возврата False, но не могу понять, как на самом деле увидеть разные строки.
Любые указатели приветствуются
Ответы:
Этот подход
df1 != df2
работает только для фреймов данных с идентичными строками и столбцами. Фактически, все оси фреймов данных сравниваются с_indexed_same
методом, и при обнаружении различий возникает исключение, даже в порядке столбцов / индексов.Если я вас понял, вы хотите найти не изменения, а симметричное различие. Для этого одним из подходов может быть объединение фреймов данных:
>>> df = pd.concat([df1, df2]) >>> df = df.reset_index(drop=True)
группа по
>>> df_gpby = df.groupby(list(df.columns))
получить индекс уникальных записей
>>> idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]
фильтр
>>> df.reindex(idx) Date Fruit Num Color 9 2013-11-25 Orange 8.6 Orange 8 2013-11-25 Apple 22.1 Red
источник
pd.concat
добавляет ли это только недостающие элементы изdf1
? Илиdf1
полностью заменяет наdf2
?pd.concat
- как здесь используется - выполняет внешнее соединение. Другими словами, он объединяет все индексы из обоих df, и это фактически поведение по умолчанию дляpd.concat()
, вот документы pandas.pydata.org/pandas-docs/stable/merging.htmlПередача фреймов данных в concat в словаре приводит к мультииндексному фрейму данных, из которого вы можете легко удалить дубликаты, в результате чего получается мультииндексный фрейм данных с различиями между фреймами данных:
import sys if sys.version_info[0] < 3: from StringIO import StringIO else: from io import StringIO import pandas as pd DF1 = StringIO("""Date Fruit Num Color 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green """) DF2 = StringIO("""Date Fruit Num Color 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange""") df1 = pd.read_table(DF1, sep='\s+') df2 = pd.read_table(DF2, sep='\s+') #%% dfs_dictionary = {'DF1':df1,'DF2':df2} df=pd.concat(dfs_dictionary) df.drop_duplicates(keep=False)
Результат:
Date Fruit Num Color DF2 4 2013-11-25 Apple 22.1 Red 5 2013-11-25 Orange 8.6 Orange
источник
dict
!Обновление и размещение, где другим будет легче найти, комментарий ling к ответу jur выше.
df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)
Тестирование с этими фреймами данных:
df1=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'], 'Fruit':['Banana','Orange','Apple','Celery'], 'Num':[22.1,8.6,7.6,10.2], 'Color':['Yellow','Orange','Green','Green'], }) df2=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'], 'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'], 'Num':[22.1,8.6,7.6,10.2,22.1,8.6], 'Color':['Yellow','Orange','Green','Green','Red','Orange'], })
Результаты в этом:
источник
Основываясь на ответе alko, который почти сработал для меня, за исключением этапа фильтрации (где я получаю :)
ValueError: cannot reindex from a duplicate axis
, вот окончательное решение, которое я использовал:# join the dataframes united_data = pd.concat([data1, data2, data3, ...]) # group the data by the whole row to find duplicates united_data_grouped = united_data.groupby(list(united_data.columns)) # detect the row indices of unique rows uniq_data_idx = [x[0] for x in united_data_grouped.indices.values() if len(x) == 1] # extract those unique values uniq_data = united_data.iloc[uniq_data_idx]
источник
IndexError: index out of bounds'
, когда пытаюсь запустить третью строку.# THIS WORK FOR ME # Get all diferent values df3 = pd.merge(df1, df2, how='outer', indicator='Exist') df3 = df3.loc[df3['Exist'] != 'both'] # If you like to filter by a common ID df3 = pd.merge(df1, df2, on="Fruit", how='outer', indicator='Exist') df3 = df3.loc[df3['Exist'] != 'both']
источник
Существует более простое решение, которое работает быстрее и лучше, и если числа отличаются, это может даже дать вам разницу в количестве:
df1_i = df1.set_index(['Date','Fruit','Color']) df2_i = df2.set_index(['Date','Fruit','Color']) df_diff = df1_i.join(df2_i,how='outer',rsuffix='_').fillna(0) df_diff = (df_diff['Num'] - df_diff['Num_'])
Здесь df_diff - это краткий обзор различий. Вы даже можете использовать его, чтобы найти разницу в количестве. В вашем примере:
Объяснение: аналогично сравнению двух списков, чтобы сделать это эффективно, мы должны сначала упорядочить их, а затем сравнить их (преобразование списка в наборы / хеширование также будет быстрым; оба являются невероятным улучшением простого цикла двойного сравнения O (N ^ 2)
Примечание: следующий код создает таблицы:
df1=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'], 'Fruit':['Banana','Orange','Apple','Celery'], 'Num':[22.1,8.6,7.6,10.2], 'Color':['Yellow','Orange','Green','Green'], }) df2=pd.DataFrame({ 'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'], 'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'], 'Num':[22.1,8.6,7.6,10.2,22.1,8.6], 'Color':['Yellow','Orange','Green','Green','Red','Orange'], })
источник
Основатель простого решения здесь:
https://stackoverflow.com/a/47132808/9656339
pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]
источник
# given df1=pd.DataFrame({'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'], 'Fruit':['Banana','Orange','Apple','Celery'], 'Num':[22.1,8.6,7.6,10.2], 'Color':['Yellow','Orange','Green','Green']}) df2=pd.DataFrame({'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'], 'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'], 'Num':[22.1,8.6,7.6,1000,22.1,8.6], 'Color':['Yellow','Orange','Green','Green','Red','Orange']}) # find which rows are in df2 that aren't in df1 by Date and Fruit df_2notin1 = df2[~(df2['Date'].isin(df1['Date']) & df2['Fruit'].isin(df1['Fruit']) )].dropna().reset_index(drop=True) # output print('df_2notin1\n', df_2notin1) # Color Date Fruit Num # 0 Red 2013-11-25 Apple 22.1 # 1 Orange 2013-11-25 Orange 8.6
источник
Получил вот такое решение. Вам это помогает?
text = """df1: 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green df2: 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange argetz45 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 118.6 Orange 2013-11-24 Apple 74.6 Green 2013-11-24 Celery 10.2 Green 2013-11-25 Nuts 45.8 Brown 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange 2013-11-26 Pear 102.54 Pale"""
.
from collections import OrderedDict import re r = re.compile('([a-zA-Z\d]+).*\n' '(20\d\d-[01]\d-[0123]\d.+\n?' '(.+\n?)*)' '(?=[ \n]*\Z' '|' '\n+[a-zA-Z\d]+.*\n' '20\d\d-[01]\d-[0123]\d)') r2 = re.compile('((20\d\d-[01]\d-[0123]\d) +([^\d.]+)(?<! )[^\n]+)') d = OrderedDict() bef = [] for m in r.finditer(text): li = [] for x in r2.findall(m.group(2)): if not any(x[1:3]==elbef for elbef in bef): bef.append(x[1:3]) li.append(x[0]) d[m.group(1)] = li for name,lu in d.iteritems(): print '%s\n%s\n' % (name,'\n'.join(lu))
результат
df1 2013-11-24 Banana 22.1 Yellow 2013-11-24 Orange 8.6 Orange 2013-11-24 Apple 7.6 Green 2013-11-24 Celery 10.2 Green df2 2013-11-25 Apple 22.1 Red 2013-11-25 Orange 8.6 Orange argetz45 2013-11-25 Nuts 45.8 Brown 2013-11-26 Pear 102.54 Pale
источник
Поскольку
pandas >= 1.1.0
у нас естьDataFrame.compare
иSeries.compare
.df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, np.NaN, 9]}) df2 = pd.DataFrame({'A': [1, 99, 3], 'B': [4, 5, 81], 'C': [7, 8, 9]}) A B C 0 1 4 7.0 1 2 5 NaN 2 3 6 9.0 A B C 0 1 4 7 1 99 5 8 2 3 81 9
df1.compare(df2) A B C self other self other self other 1 2.0 99.0 NaN NaN NaN 8.0 2 NaN NaN 6.0 81.0 NaN NaN
источник
Следует отметить одну важную деталь: ваши данные имеют повторяющиеся значения индекса , поэтому для выполнения любого прямого сравнения нам нужно сделать все как уникальное,
df.reset_index()
и поэтому мы можем выполнять выборку на основе условий. Как только в вашем случае индекс определен, я предполагаю, что вы хотели бы сохранить индекс, поэтому существует однострочное решение:[~df2.reset_index().isin(df1.reset_index())].dropna().set_index('Date')
Как только цель с питонической точки зрения - улучшить читаемость, мы можем немного сломаться:
# keep the index name, if it does not have a name it uses the default name index_name = df.index.name if df.index.name else 'index' # setting the index to become unique df1 = df1.reset_index() df2 = df2.reset_index() # getting the differences to a Dataframe df_diff = df2[~df2.isin(df1)].dropna().set_index(index_name)
источник
Надеюсь, это будет вам полезно. ^ о ^
df1 = pd.DataFrame({'date': ['0207', '0207'], 'col1': [1, 2]}) df2 = pd.DataFrame({'date': ['0207', '0207', '0208', '0208'], 'col1': [1, 2, 3, 4]}) print(f"df1(Before):\n{df1}\ndf2:\n{df2}") """ df1(Before): date col1 0 0207 1 1 0207 2 df2: date col1 0 0207 1 1 0207 2 2 0208 3 3 0208 4 """ old_set = set(df1.index.values) new_set = set(df2.index.values) new_data_index = new_set - old_set new_data_list = [] for idx in new_data_index: new_data_list.append(df2.loc[idx]) if len(new_data_list) > 0: df1 = df1.append(new_data_list) print(f"df1(After):\n{df1}") """ df1(After): date col1 0 0207 1 1 0207 2 2 0208 3 3 0208 4 """
источник
Я попробовал этот метод, и он сработал. Надеюсь, это тоже поможет:
"""Identify differences between two pandas DataFrames""" df1.sort_index(inplace=True) df2.sort_index(inplace=True) df_all = pd.concat([df1, df12], axis='columns', keys=['First', 'Second']) df_final = df_all.swaplevel(axis='columns')[df1.columns[1:]] df_final[df_final['change this to one of the columns'] != df_final['change this to one of the columns']]
источник