web-dev-qa-db-fra.com

Comparer les bases de données de deux pandas pour les différences

J'ai un script qui met à jour 5-10 colonnes de données, mais parfois le csv de départ sera identique au csv de fin, alors au lieu d'écrire un fichier csv identique, je ne veux rien faire ... 

Comment comparer deux images pour vérifier si elles sont identiques ou non?

csvdata = pandas.read_csv('csvfile.csv')
csvdata_old = csvdata

# ... do stuff with csvdata dataframe

if csvdata_old != csvdata:
    csvdata.to_csv('csvfile.csv', index=False)

Des idées?

29
Ryflex

Vous devez également faire attention à créer une copie du DataFrame, sinon csvdata_old sera mis à jour avec csvdata (car il pointe sur le même objet):

csvdata_old = csvdata.copy()

Pour vérifier si elles sont égales, vous pouvez utiliser assert_frame_equal comme dans cette réponse :

from pandas.util.testing import assert_frame_equal
assert_frame_equal(csvdata, csvdata_old)

Vous pouvez envelopper ceci dans une fonction avec quelque chose comme:

try:
    assert_frame_equal(csvdata, csvdata_old)
    return True
except:  # appeantly AssertionError doesn't catch all
    return False

Il y avait une discussion sur une meilleure façon ...

41
Andy Hayden

Je ne sais pas si cela existait au moment où la question a été posée, mais les pandas ont maintenant une fonction intégrée pour tester l'égalité entre deux cadres de données: http://pandas.pydata.org/pandas-docs/stable/generated/pandas .DataFrame.equals.html .

10
sobes

Vérifiez en utilisant: df_1.equals (df_2) # Retourne Vrai ou Faux, détails ci-dessous

In [45]: import numpy as np

In [46]: import pandas as pd

In [47]: np.random.seed(5)

In [48]: df_1= pd.DataFrame(np.random.randn(3,3))

In [49]: df_1
Out[49]: 
          0         1         2
0  0.441227 -0.330870  2.430771
1 -0.252092  0.109610  1.582481
2 -0.909232 -0.591637  0.187603

In [50]: np.random.seed(5)

In [51]: df_2= pd.DataFrame(np.random.randn(3,3))

In [52]: df_2
Out[52]: 
          0         1         2
0  0.441227 -0.330870  2.430771
1 -0.252092  0.109610  1.582481
2 -0.909232 -0.591637  0.187603

In [53]: df_1.equals(df_2)
Out[53]: True


In [54]: df_3= pd.DataFrame(np.random.randn(3,3))

In [55]: df_3
Out[55]: 
          0         1         2
0 -0.329870 -1.192765 -0.204877
1 -0.358829  0.603472 -1.664789
2 -0.700179  1.151391  1.857331

In [56]: df_1.equals(df_3)
Out[56]: False
7
Surya

Ceci compare les values ​​de deux cadres de données, notez que le nombre de lignes/colonnes doit être identique entre les tables

comparison_array = table.values == expected_table.values
print (comparison_array)

>>>[[True, True, True]
    [True, False, True]]

if False in comparison_array:
    print ("Not the same")

#Return the position of the False values
np.where(comparison_array==False)

>>>(array([1]), array([1]))

Vous pouvez ensuite utiliser ces informations d'index pour renvoyer la valeur qui ne correspond pas entre les tables. Comme il est indexé à zéro, il fait référence au second tableau en 2e position, ce qui est correct.

5
Tristan Forward

Je ne suis pas sûr que cela soit utile ou non, mais j'ai regroupé cette méthode rapide en python pour ne renvoyer que les différences entre deux images contenant les mêmes colonnes et la même forme.

def get_different_rows(source_df, new_df):
    """Returns just the rows from the new dataframe that differ from the source dataframe"""
    merged_df = source_df.merge(new_df, indicator=True, how='outer')
    changed_rows_df = merged_df[merged_df['_merge'] == 'right_only']
    return changed_rows_df.drop('_merge', axis=1)
4
Tom Chapin

Une comparaison plus précise devrait vérifier les noms d'index séparément, car DataFrame.equals ne le teste pas. Toutes les autres propriétés (valeurs d'index (single/multi-index), valeurs, colonnes, dtypes) sont vérifiées correctement.

df1 = pd.DataFrame([[1, 'a'], [2, 'b'], [3, 'c']], columns=['num', 'name'])
df1 = df1.set_index('name')
df2 = pd.DataFrame([[1, 'a'], [2, 'b'], [3, 'c']], columns=['num', 'another_name'])
df2 = df2.set_index('another_name')

df1.equals(df2)
True

df1.index.names == df2.index.names
False

Remarque: l'utilisation de index.names au lieu de index.name le fait également fonctionner pour les images multi-indexées.

4
Dennis Golomazov

Dans mon cas, j’ai eu une erreur étrange, alors que même si les indices, les noms de colonnes .__ et les valeurs étaient identiques, la variable DataFrames ne correspondait pas. Je l'ai retrouvé jusqu'aux types de données , Et il semble que pandas puisse parfois utiliser différents types de données, , Ce qui entraîne de tels problèmes

Par exemple: 

param2 = pd.DataFrame({'a': [1]}) param1 = pd.DataFrame({'a': [1], 'b': [2], 'c': [2], 'step': ['alpha']})

si vous cochez param1.dtypes et param2.dtypes, vous constaterez que 'a' est de type type object pour param1 et de type int64 pour param2. Maintenant, si vous manipulez une manipulation en utilisant param1 et param2, les autres paramètres Du cadre de données différeront de ceux par défaut.

Ainsi, après la génération de la structure de données finale, même si les valeurs réelles imprimées Sont identiques, final_df1.equals(final_df2), peut s'avérer être Pas égal, car ces paramètres identiques à Axis 1, ObjectBlock, IntBlock peut ne pas être la même chose.

Un moyen facile de contourner ce problème et de comparer les valeurs consiste à utiliser

final_df1==final_df2.

Cependant, cela fera une comparaison élément par élément, donc cela ne fonctionnera pas si vous l'utilisez pour affirmer une déclaration, par exemple dans pytest.

TL; DR

Ce qui fonctionne bien c'est

all(final_df1 == final_df2).

Ceci fait une comparaison élément par élément, tout en négligeant les paramètres non importants pour la comparaison.

TL; DR2

Si vos valeurs et vos index sont identiques, mais que final_df1.equals(final_df2) affiche False, vous pouvez utiliser final_df1._data et final_df2._data pour vérifier le reste des éléments des images.

1
alpha_989