Comparando dos marcos de datos de pandas por diferencias

Tengo un script que actualiza 5-10 columnas de datos, pero a veces el csv de inicio será idéntico al csv de fin, así que en lugar de escribir un archivo csv idéntico, quiero que no haga nada …

¿Cómo puedo comparar dos marcos de datos para verificar si son iguales o no?

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) 

¿Algunas ideas?

Related of "Comparando dos marcos de datos de pandas por diferencias"

También debe tener cuidado de crear una copia del DataFrame, de lo contrario, csvdata_old se actualizará con csvdata (ya que apunta al mismo objeto):

 csvdata_old = csvdata.copy() 

Para verificar si son iguales, puede usar assert_frame_equal como en esta respuesta :

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

Puedes envolver esto en una función con algo como:

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

Hubo discusión de una mejor manera …

No estoy seguro de si esto existía en el momento en que se publicó la pregunta, pero pandas ahora tiene una función incorporada para probar la igualdad entre dos marcos de datos: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame .equals.html .

Verifique usando: df_1.equals (df_2) # Devuelve Verdadero o Falso , detalles a continuación

 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 

Una comparación más precisa debe verificar los nombres de los índices por separado, ya que DataFrame.equals no realiza pruebas para eso. Todas las demás propiedades (valores de índice (único / multiindex), valores, columnas, tipos) se verifican correctamente.

 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 

Nota: el uso de index.names lugar de index.name hace que funcione también para index.name de index.name de múltiples índices.

No estoy seguro de si esto es útil o no, pero combiné este método rápido de Python para devolver solo las diferencias entre dos marcos de datos que tienen la misma columna y forma.

 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) 

Esto compara los valores de dos marcos de datos. Tenga en cuenta que el número de filas / columnas debe ser el mismo entre las tablas.

 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])) 

Luego podría usar esta información de índice para devolver el valor que no coincide entre las tablas. Como está indexado a cero, se refiere a la 2ª matriz en la 2ª posición, que es correcta.

En mi caso, tuve un error extraño, por el cual, aunque los índices, los nombres de columna y los valores eran iguales, los DataFrames coincidían. Lo rastreé hasta los tipos de datos, y parece que los pandas veces pueden usar tipos de datos diferentes, lo que resulta en tales problemas.

Por ejemplo:

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

Si param1.dtypes y param2.dtypes , encontrará que ‘a’ es de tipo object para param1 y de tipo int64 para param2 . Ahora, si realiza alguna manipulación utilizando una combinación de param1 y param2 , otros parámetros del dataframe se desviarán de los predeterminados.

Por lo tanto, después de que se genere el dataframe final, aunque los valores reales que se imprimen son iguales, final_df1.equals(final_df2) , puede que no sean iguales, ya que esos parámetros de tipo ObjectBlock como Axis 1 , ObjectBlock , IntBlock pueden no mismo.

Una forma fácil de evitar esto y comparar los valores es usar

final_df1==final_df2 .

Sin embargo, esto hará una comparación elemento por elemento, por lo que no funcionará si lo está utilizando para afirmar una statement, por ejemplo, en pytest .

TL; DR

Lo que funciona bien es

all(final_df1 == final_df2) .

Esto hace una comparación elemento por elemento, mientras que descuida los parámetros que no son importantes para la comparación.

TL; DR2

Si sus valores e índices son iguales, pero final_df1.equals(final_df2) muestra False , puede usar final_df1._data y final_df2._data para verificar el rest de los elementos de los marcos de datos.