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.equals
daar 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.names
te gebruiken in plaats van index.name
werkt 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 DataFrames
niet overeen. Ik volgde het naar de
datatypes, en het lijkt erop dat pandas
soms 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.dtypes
en param2.dtypes
aanvinkt, zul je zien dat ‘a’ van
typ object
voor param1
en is van het type int64
voor param2
. Nu, als je dat doet
enige manipulatie met een combinatie van param1
en 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
,
IntBlock
is 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._data
gebruiken en final_df2._data
om 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:
Opmerking: voeg tot de volgende uitgave van panda’s het argument sort=False
toe 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())