比较两个熊猫数据框架的差异

我有一个脚本更新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)

有什么想法吗?

139919 次浏览

您还需要注意创建 DataFrame 的副本,否则 csvdata _ old 将使用 csvdata 进行更新(因为它指向同一个对象) :

csvdata_old = csvdata.copy()

要检查它们是否相等,可以使用 像这个答案一样使用 asser_ frame _ equals:

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

他们讨论了一个更好的方法。

这比较了两个数据框架的 价值观,注意表之间需要相同的行/列数

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

然后可以使用此索引信息返回表之间不匹配的值。因为它的索引为零,所以它指的是第二个位置的第二个数组,这是正确的。

不确定这个问题发布时是否存在,但是熊猫现在有一个内置的功能来测试两个数据帧之间的相等性: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.equals.html

检查使用: 等于(df _ 2) # 返回真或假详情如下:

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

更精确的比较应该单独检查索引名称,因为 DataFrame.equals不对此进行测试。它正确地检查了所有其他属性(索引值(单个/多索引)、值、列和 dtype)。

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也可以用于多索引数据框架。

不确定这是否有帮助,但是我将这个快速的 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)

在我的情况下,我有一个奇怪的错误,即即使索引,列名 值相同时,DataFrames不匹配 数据类型,似乎 pandas有时可以使用不同的数据类型, 导致这些问题

例如:

Param2 = pd.DataFrame ({‘ a’: [1]}) Param1 = pd.DataFrame ({‘ a’: [1] ,‘ b’: [2] ,‘ c’: [2] ,‘ step’: [‘ alpha’]})

如果你检查 param1.dtypesparam2.dtypes,你会发现‘ a’是 为 param1键入 object,为 param2键入 int64 一些操作使用 param1param2的组合,其他 数据框架的参数将偏离默认参数。

所以在生成最终的数据框之后,即使 打印出来的是相同的,final_df1.equals(final_df2),可能是 不相等,因为这些小参数像 Axis 1ObjectBlock, IntBlock可能不一样。

解决这个问题并比较值的一个简单方法是使用

final_df1==final_df2.

但是,这将逐个元素进行比较,因此如果您 正在使用它来断言一个语句,例如在 pytest中。

DR

有效的办法是

all(final_df1 == final_df2).

这将逐个元素进行比较,同时忽略参数 比较起来很重要。

DR2

如果您的值和索引是相同的,但是 final_df1.equals(final_df2)显示的是 False,那么您可以使用 final_df1._datafinal_df2._data来检查数据帧的其余元素。

拉出对称差异:

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)

我希望下面的代码片段能对您有所帮助!

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