Сравнение двух данных и получение различий
У меня есть два кадра данных. Примеры:
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
Каждая датафрейма имеет Date как индекс. Оба блока данных имеют одинаковую структуру.
Что я хочу сделать, сравнивают эти два фрейма данных и находят, какие строки находятся в df2, которые не находятся в df1. Я хочу сравнить дату (индекс) и первый столбец (Banana, APple и т.д.), Чтобы увидеть, существуют ли они в df2 vs df1.
Я пробовал следующее:
Для первого подхода я получаю эту ошибку: "Исключение: может сравнивать только объекты с меткой DataFrame с идентичной меткой" . Я попытался удалить Date как индекс, но получить ту же ошибку.
В третьем подходе я верю, что assert возвращает False, но не может понять, как реально видеть разные строки.
Любые указатели будут приветствоваться
Ответы
Ответ 1
Этот подход df1 != df2
работает только для фреймов данных с одинаковыми строками и столбцами. Фактически, все оси dataframes сравниваются с методом _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
Ответ 2
Передача фреймов данных для конкататации в словаре приводит к мультииндексному фрейму данных, из которого вы можете легко удалить дубликаты, что приводит к мультииндексному фрейму данных с различиями между фреймами данных:
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
Ответ 3
Основываясь на ответе 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]
Ответ 4
Существует более простое решение, которое выполняется быстрее и лучше,
и если числа разные, это может даже дать вам различия в величинах:
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 - краткий обзор различий. Вы можете даже использовать его, чтобы найти различия в количествах. В вашем примере:
![введите описание изображения здесь]()
Объяснение:
Аналогично сравнению двух списков, чтобы сделать это эффективно, мы должны сначала заказать их, а затем сравнить их (преобразование списка в sets/hashing также будет быстрым, оба являются невероятным улучшением простого двойного цикла сравнения 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'],
})
Ответ 5
# 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
Ответ 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
Ответ 7
Найти простое решение здесь:
fooobar.com/questions/6947117/...
pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]
Ответ 8
Обновление и размещение, где-то другим будет легче найти, комментируя свой ответ выше.
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'],
})
Результаты в этом:
![enter image description here]()
Ответ 9
Одна важная деталь, на которую следует обратить внимание, это то, что ваши данные имеют повторяющиеся значения индекса, поэтому для выполнения любого простого сравнения нам нужно сделать все уникальным с помощью 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)
Ответ 10
Надеюсь, это будет полезно для вас. ^ О ^
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
"""
Ответ 11
Я попробовал этот метод, и он работал. Я надеюсь, что это тоже может помочь:
"""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']]