Eu tenho dois dataframes. Exemplos:
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
Cada dataframe tem a Data como índice. Ambos os dataframes têm a mesma estrutura.
O que eu quero fazer é comparar esses dois dataframes e descobrir quais linhas estão no df2 que não estão no df1. Quero comparar a data (índice) e a primeira coluna (Banana, APple, etc) para ver se eles existem no df2 vs df1.
Eu tentei o seguinte:
- Saída da diferença em dois dataframes Pandas lado a lado - destacando a diferença
- Comparando dois dataframes pandas para diferenças
Para a primeira abordagem, recebo este erro: "Exceção: Só pode comparar objetos DataFrame com rótulos idênticos" . Tentei remover a data como índice, mas obtive o mesmo erro.
Na terceira abordagem , obtenho a declaração para retornar False, mas não consigo descobrir como realmente ver as diferentes linhas.
Qualquer sugestão seria bem-vinda
Respostas:
Esta abordagem,
df1 != df2
funciona apenas para dataframes com linhas e colunas idênticas. Na verdade, todos os eixos dos dataframes são comparados com o_indexed_same
método, e a exceção é levantada se diferenças encontradas, mesmo na ordem das colunas / índices.Se entendi bem, você não quer encontrar mudanças, mas diferenças simétricas. Para isso, uma abordagem pode ser concatenar dataframes:
>>> df = pd.concat([df1, df2]) >>> df = df.reset_index(drop=True)
agrupar por
>>> df_gpby = df.groupby(list(df.columns))
obter índice de registros únicos
>>> idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]
filtro
>>> df.reindex(idx) Date Fruit Num Color 9 2013-11-25 Orange 8.6 Orange 8 2013-11-25 Apple 22.1 Red
fonte
pd.concat
adiciona apenas os itens ausentes dodf1
? Ou substituidf1
completamente pordf2
?pd.concat
- como usado aqui - faz uma junção externa. Em outras palavras, ele junta todos os índices de ambos os df's e este é de fato o comportamento padrão parapd.concat()
, aqui está o docs pandas.pydata.org/pandas-docs/stable/merging.htmlPassar os dataframes para concatenar em um dicionário resulta em um dataframe multi-índice do qual você pode facilmente excluir as duplicatas, o que resulta em um dataframe multi-índice com as diferenças entre os dados:
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)
Resultado:
Date Fruit Num Color DF2 4 2013-11-25 Apple 22.1 Red 5 2013-11-25 Orange 8.6 Orange
fonte
dict
!Atualizar e colocar, em algum lugar, será mais fácil para os outros a encontrar, ling 's comentário sobre jur ' s resposta acima.
df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)
Testando com estes DataFrames:
# with import pandas as pd 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'], })
Resultados neste:
# for df1 Date Fruit Num Color 0 2013-11-24 Banana 22.1 Yellow 1 2013-11-24 Orange 8.6 Orange 2 2013-11-24 Apple 7.6 Green 3 2013-11-24 Celery 10.2 Green # for df2 Date Fruit Num Color 0 2013-11-24 Banana 22.1 Yellow 1 2013-11-24 Orange 8.6 Orange 2 2013-11-24 Apple 7.6 Green 3 2013-11-24 Celery 10.2 Green 4 2013-11-25 Apple 22.1 Red 5 2013-11-25 Orange 8.6 Orange # for df_diff Date Fruit Num Color 4 2013-11-25 Apple 22.1 Red 5 2013-11-25 Orange 8.6 Orange
fonte
Com base na resposta de alko que quase funcionou para mim, exceto para a etapa de filtragem (onde obtenho:)
ValueError: cannot reindex from a duplicate axis
, aqui está a solução final que usei:# 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]
fonte
IndexError: index out of bounds'
, quando tento executar a terceira linha.# 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']
fonte
Existe uma solução mais simples que é mais rápida e melhor e, se os números forem diferentes, pode até apresentar diferenças de quantidades:
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_'])
Aqui, df_diff é uma sinopse das diferenças. Você pode até usá-lo para encontrar as diferenças nas quantidades. No seu exemplo:
Explicação: Da mesma forma que comparar duas listas, para fazer isso de forma eficiente, devemos primeiro ordená-las e depois compará-las (converter a lista em conjuntos / hash também seria rápido; ambos são uma melhoria incrível para o loop de comparação dupla simples O (N ^ 2)
Nota: o código a seguir produz as tabelas:
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'], })
fonte
Crie uma solução simples aqui:
https://stackoverflow.com/a/47132808/9656339
pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]
fonte
# 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
fonte
Uma vez
pandas >= 1.1.0
que temosDataFrame.compare
eSeries.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
fonte
Eu tenho essa solução. Isso te ajuda?
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))
resultado
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
fonte
Um detalhe importante a ser observado é que seus dados têm valores de índice duplicados , portanto, para realizar qualquer comparação direta, precisamos transformar tudo como único com
df.reset_index()
e, portanto, podemos realizar seleções com base nas condições. Uma vez que, no seu caso, o índice esteja definido, suponho que você gostaria de mantê-lo para que haja uma solução de uma linha:[~df2.reset_index().isin(df1.reset_index())].dropna().set_index('Date')
Uma vez que o objetivo de uma perspectiva pitônica é melhorar a legibilidade, podemos quebrar um pouco:
# 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)
fonte
Espero que isso seja útil para você. ^ o ^
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 """
fonte
Tentei esse método e funcionou. Espero que também possa ajudar:
"""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']]
fonte