Сравнение двух фреймов данных pandas для различий
У меня есть script обновление 5-10 столбцов данных, но иногда начало csv будет идентично концу csv, поэтому вместо написания идентичного csvfile я хочу, чтобы он ничего не делал...
Как я могу сравнить два фрейма данных, чтобы проверить, одинаковы они или нет?
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)
Любые идеи?
Ответы
Ответ 1
Также вам нужно быть осторожным, чтобы создать копию DataFrame, иначе csvdata_old будет обновляться csvdata (поскольку он указывает на тот же объект):
csvdata_old = csvdata.copy()
Чтобы проверить, равны ли они, вы можете использовать assert_frame_equal, как в этом ответе:
from pandas.util.testing import assert_frame_equal
assert_frame_equal(csvdata, csvdata_old)
Вы можете обернуть это в функцию с чем-то вроде:
try:
assert_frame_equal(csvdata, csvdata_old)
return True
except: # appeantly AssertionError doesn't catch all
return False
Было обсуждение лучшего пути...
Ответ 2
Не уверен, что это существовало во время публикации вопроса, но pandas теперь имеет встроенную функцию для проверки равенства между двумя файлами данных: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.equals.html.
Ответ 3
Проверить использование: df_1.equals(df_2) # Возвращает True или False, подробнее здесь
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
Ответ 4
Не уверен, что это полезно или нет, но я взломал этот быстрый метод python для возврата только различий между двумя файлами данных, которые имеют одинаковые столбцы и форму.
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)
Ответ 5
При этом сравниваются значения двух фреймов данных, отмечая, что количество строк/столбцов в таблицах должно быть одинаковым
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]))
Затем вы можете использовать эту информацию индекса для возврата значения, которое не совпадает между таблицами. Поскольку он индексируется нулем, он ссылается на 2-й массив во 2-й позиции, что является правильным.
Ответ 6
Более точное сравнение должно проверять имена индексов отдельно, потому что DataFrame.equals
не проверяет это. Все остальные свойства (значения индекса (single/multiindex), значения, столбцы, типы данных) проверяются корректно.
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
Примечание: использование index.names
вместо index.name
заставляет его работать и с мультииндексированными файлами данных.
Ответ 7
В моем случае у меня произошла странная ошибка, из-за которой, хотя индексы и имена столбцов
и значения были одинаковыми, DataFrames
не совпадает. Я отследил это до
типы данных, и кажется, что pandas
может иногда использовать разные типы данных,
что приводит к таким проблемам
Например:
param2 = pd.DataFrame({'a': [1]})
param1 = pd.DataFrame({'a': [1], 'b': [2], 'c': [2], 'step': ['alpha']})
если вы проверите param1.dtypes
и param2.dtypes
, вы обнаружите, что "а" имеет
введите object
для param1
и тип int64
для param2
. Теперь, если вы делаете
некоторые манипуляции с использованием комбинации param1
и param2
, другие
параметры кадра данных будут отличаться от параметров по умолчанию.
Таким образом, после генерации окончательного кадра данных, даже если фактические значения
распечатаны одинаково, final_df1.equals(final_df2)
, может оказаться
не равны, потому что такие параметры samll, как Axis 1
, ObjectBlock
,
IntBlock
может не совпадать.
Простой способ обойти это и сравнить значения - использовать
final_df1==final_df2
.
Тем не менее, это будет делать поэлементное сравнение, поэтому он не будет работать, если вы
используют его для утверждения оператора, например, в pytest
.
TL; DR
Что хорошо работает, так это
all(final_df1 == final_df2)
.
Это делает поэлементное сравнение, игнорируя параметры, не
важно для сравнения.
TL; DR2
Если ваши значения и индексы совпадают, но final_df1.equals(final_df2)
показывает False
, вы можете использовать final_df1._data
и final_df2._data
, чтобы проверить остальные элементы кадров данных.
Ответ 8
Чтобы вывести симметричные различия:
df_diff = pd.concat([df1,df2]).drop_duplicates(keep=False)
Например:
df1 = pd.DataFrame({
'num': [1, 4, 3],
'name': ['a', 'b', 'c'],
})
df2 = pd.DataFrame({
'num': [1, 2, 3],
'name': ['a', 'b', 'd'],
})
будет давать:
![enter image description here]()
Примечание: до следующего выпуска панд, чтобы избежать предупреждения о том, как будет установлен аргумент сортировки в будущем, просто добавьте аргумент sort=False
. Как показано ниже:
df_diff = pd.concat([df1,df2], sort=False).drop_duplicates(keep=False)