J'ai deux dataframes. Exemples:
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
Chaque dataframe a la date comme index. Les deux dataframes ont la même structure.
Ce que je veux faire, c'est comparer ces deux dataframes et trouver quelles lignes sont dans df2 qui ne sont pas dans df1. Je veux comparer la date (index) et la première colonne (Banana, APple, etc.) pour voir si elles existent dans df2 vs df1.
J'ai essayé ce qui suit:
- Sortie de la différence dans deux dataframes Pandas côte à côte - soulignant la différence
- Comparaison de deux dataframes pandas pour les différences
Pour la première approche, j'obtiens cette erreur: "Exception: ne peut comparer que des objets DataFrame étiquetés de manière identique" . J'ai essayé de supprimer la date comme index mais j'obtiens la même erreur.
Sur la troisième approche , j'obtiens l'assert pour retourner False mais je ne peux pas comprendre comment voir réellement les différentes lignes.
Tous les pointeurs seraient les bienvenus
Réponses:
Cette approche
df1 != df2
ne fonctionne que pour les dataframes avec des lignes et des colonnes identiques. En fait, tous les axes des dataframes sont comparés à la_indexed_same
méthode, et une exception est déclenchée si des différences sont trouvées, même dans l'ordre des colonnes / index.Si je vous ai bien compris, vous ne voulez pas trouver de changements, mais une différence symétrique. Pour cela, une approche pourrait être de concaténer des dataframes:
>>> df = pd.concat([df1, df2]) >>> df = df.reset_index(drop=True)
par groupe
>>> df_gpby = df.groupby(list(df.columns))
obtenir l'index des enregistrements uniques
>>> idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]
filtre
>>> df.reindex(idx) Date Fruit Num Color 9 2013-11-25 Orange 8.6 Orange 8 2013-11-25 Apple 22.1 Red
la source
pd.concat
ajoute uniquement les éléments manquants dudf1
? Ou remplace-t-ildf1
complètement pardf2
?pd.concat
- tel qu'utilisé ici - fait une jointure externe. En d'autres termes, il joint tous les index des deux df et c'est en fait le comportement par défaut pourpd.concat()
, voici la documentation pandas.pydata.org/pandas-docs/stable/merging.htmlPasser les dataframes à concat dans un dictionnaire, aboutit à une dataframe multi-index à partir de laquelle vous pouvez facilement supprimer les doublons, ce qui se traduit par une dataframe multi-index avec les différences entre les dataframes:
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)
Résultat:
Date Fruit Num Color DF2 4 2013-11-25 Apple 22.1 Red 5 2013-11-25 Orange 8.6 Orange
la source
dict
!Mise à jour et placement, quelque part qu'il sera plus facile pour les autres de trouver, le commentaire de ling sur la réponse de jur ci-dessus.
df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)
Test avec ces dataframes:
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'], })
Résultats en ceci:
la source
En s'appuyant sur la réponse d'alko qui a presque fonctionné pour moi, à l'exception de l'étape de filtrage (où j'obtiens :)
ValueError: cannot reindex from a duplicate axis
, voici la solution finale que j'ai utilisée:# 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]
la source
IndexError: index out of bounds'
, lorsque j'essaye d'exécuter la troisième ligne.# 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']
la source
Il existe une solution plus simple, plus rapide et meilleure, et si les nombres sont différents, cela peut même vous donner des différences de quantités:
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_'])
Ici, df_diff est un synopsis des différences. Vous pouvez même l'utiliser pour trouver les différences de quantités. Dans votre exemple:
Explication: De la même manière que pour comparer deux listes, pour le faire efficacement, nous devons d'abord les ordonner puis les comparer (la conversion de la liste en ensembles / hachage serait également rapide; les deux sont une amélioration incroyable de la simple double boucle de comparaison O (N ^ 2)
Remarque: le code suivant produit les tables:
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'], })
la source
Fonder une solution simple ici:
https://stackoverflow.com/a/47132808/9656339
pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]
la source
# 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
la source
J'ai cette solution. Cela vous aide-t-il?
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))
résultat
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
la source
Depuis que
pandas >= 1.1.0
nous avonsDataFrame.compare
etSeries.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
la source
Un détail important à noter est que vos données ont des valeurs d'index en double.Par conséquent, pour effectuer une comparaison simple, nous devons tout rendre unique
df.reset_index()
et nous pouvons donc effectuer des sélections en fonction des conditions. Une fois que dans votre cas, l'index est défini, je suppose que vous souhaitez conserver l'index afin qu'il existe une solution en une ligne:[~df2.reset_index().isin(df1.reset_index())].dropna().set_index('Date')
Une fois que l'objectif d'un point de vue pythonique est d'améliorer la lisibilité, nous pouvons casser un peu:
# 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)
la source
J'espère que cela vous sera utile. ^ 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 """
la source
J'ai essayé cette méthode et cela a fonctionné. J'espère que cela peut aussi aider:
"""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']]
la source