Подтвердить что ты не робот

Сравнение двух фреймов данных 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)

Любые идеи?

4b9b3361

Ответ 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

Было обсуждение лучшего пути...

Ответ 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)