Twee panda-dataframes vergelijken op verschillen

Ik heb een script dat 5-10 kolommen aan gegevens bijwerkt, maar soms is het begin-csv identiek aan het eind-csv, dus in plaats van een identiek csv-bestand te schrijven, wil ik dat het niets doet…

Hoe kan ik twee dataframes vergelijken om te controleren of ze hetzelfde zijn of niet?

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)

Enig idee?


Antwoord 1, autoriteit 100%

Je moet ook voorzichtig zijn met het maken van een kopie van het DataFrame, anders wordt de csvdata_old bijgewerkt met csvdata (omdat het naar hetzelfde object verwijst):

csvdata_old = csvdata.copy()

Om te controleren of ze gelijk zijn, kunt u gebruik assert_frame_equal zoals in dit antwoord:

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

Je kunt dit in een functie inpakken met zoiets als:

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

Er was een discussie over een betere manier…


Antwoord 2, autoriteit 43%

Ik weet niet zeker of dit nuttig is of niet, maar ik heb deze snelle python-methode samengesteld om alleen de verschillen tussen twee dataframes te retourneren die beide dezelfde kolommen en vorm hebben.

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)

Antwoord 3, autoriteit 25%

Niet zeker of dit bestond op het moment dat de vraag werd gepost, maar pandas heeft nu een ingebouwde functie om de gelijkheid tussen twee dataframes te testen: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.equals.html.


Antwoord 4, autoriteit 16%

Een nauwkeurigere vergelijking zou de indexnamen afzonderlijk moeten controleren, omdat DataFrame.equalsdaar niet op test. Alle andere eigenschappen (indexwaarden (single/multiindex), waarden, kolommen, dtypes) worden er correct door gecontroleerd.

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

Opmerking: door index.nameste gebruiken in plaats van index.namewerkt het ook voor multi-geïndexeerde dataframes.


Antwoord 5, autoriteit 13%

Controleer met: df_1.equals(df_2)# Retourneert waar of niet waar, details hieronder

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

Antwoord 6, autoriteit 9%

Hiermee worden de waardenvan twee dataframes vergeleken. Let op: het aantal rijen/kolommen moet tussen tabellen gelijk zijn

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

U kunt deze indexinformatie dan gebruiken om de waarde te retourneren die niet overeenkomt tussen tabellen. Omdat het nul geïndexeerd is, verwijst het naar de 2e array op de 2e positie, wat correct is.


Antwoord 7, autoriteit 8%

In mijn geval had ik een rare fout, waarbij hoewel de indices, kolomnamen
en waarden hetzelfde waren, kwamen de DataFramesniet overeen. Ik volgde het naar de
datatypes, en het lijkt erop dat pandassoms verschillende datatypes kunnen gebruiken,
met zulke problemen tot gevolg

Bijvoorbeeld:


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

als je param1.dtypesen param2.dtypesaanvinkt, zul je zien dat ‘a’ van
typ objectvoor param1en is van het type int64voor param2. Nu, als je dat doet
enige manipulatie met een combinatie van param1en param2, andere
parameters van het dataframe zullen afwijken van de standaard.

Dus nadat het laatste dataframe is gegenereerd, ook al zijn de werkelijke waarden die
zijn afgedrukt, zijn hetzelfde, final_df1.equals(final_df2), kan blijken te zijn
niet gelijk, omdat die kleine parameters zoals Axis 1, ObjectBlock,
IntBlockis misschien niet hetzelfde.

Een gemakkelijke manier om dit te omzeilen en de waarden te vergelijken, is door gebruik te maken van

final_df1==final_df2.

Dit zal echter een element voor element vergelijking maken, dus het zal niet werken als u
gebruiken het om een ​​statement te maken, bijvoorbeeld in pytest.

TL;DR

Wat goed werkt, is

all(final_df1 == final_df2).

Dit doet een element voor element vergelijking, terwijl de parameters niet worden verwaarloosd
belangrijk ter vergelijking.

TL;DR2

Als uw waarden en indices hetzelfde zijn, maar final_df1.equals(final_df2)toont False, kunt u final_df1._datagebruiken en final_df2._dataom de rest van de elementen van de dataframes te controleren.


Antwoord 8, autoriteit 8%

Om de symmetrische verschillen eruit te halen:

df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)

Bijvoorbeeld:

df1 = pd.DataFrame({
    'num': [1, 4, 3],
    'name': ['a', 'b', 'c'],
})
df2 = pd.DataFrame({
    'num': [1, 2, 3],
    'name': ['a', 'b', 'd'],
})

Zal opleveren:

voer hier de afbeeldingsbeschrijving in

Opmerking: voeg tot de volgende uitgave van panda’s het argument sort=Falsetoe om de waarschuwing over hoe het sort-argument in de toekomst zal worden ingesteld te vermijden. Zoals hieronder:

df_diff = pd.concat([df1,df2], sort=False).drop_duplicates(keep=False)

Antwoord 9

Ik hoop dat dit onderstaande codefragment je helpt!

import pandas as pd
import datacompy
df_old_original = pd.DataFrame([[1, 1, 1, 1], [2, 2, 2, 2], [7, 7, 7, 7], [3, 3, 3, 3], [4, 4, 4, 4], [7, 7, 7, 7], [5, 5, 5, 5], [6, 6, 6, 6]], columns=['A', 'B', 'C', 'D'], index=[0, 1, 2, 3, 4, 5, 6, 7], dtype=object)
df_new_original = pd.DataFrame([[None, None, None, None], [1, 1, 1, 1], [2, 2, 2, 2], [8, 8, 8, 8], [3, 3, 3, 3], [4, 4, 4, 4], [7, 7, 7, 7], [5, 5, 5, 5], [None, None, None, None]], columns=['A', 'B', 'C', 'D'], index=[0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=object)
compare = datacompy.Compare(df_old_original, df_new_original, join_columns=['A', 'B', 'C', 'D'], abs_tol=0, rel_tol=0, df1_name='Old', df2_name='New')
changes_in_old_df = compare.df1_unq_rows
changes_in_new_df = compare.df2_unq_rows
print(changes_in_old_df)
print(changes_in_new_df)
print(Compare.report())

Other episodes