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

Posted

技术标签:

【中文标题】比较两个熊猫数据框的差异【英文标题】:Comparing two pandas dataframes for differences 【发布时间】:2013-11-23 21:58:07 【问题描述】:

我有一个更新 5-10 列数据的脚本,但有时起始 csv 将与结束 csv 相同,因此我不想编写相同的 csv 文件,而是希望它什么都不做......

如何比较两个数据框以检查它们是否相同?

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)

有什么想法吗?

【问题讨论】:

不是 Pandas 专家,但不应该进行正常的相等比较工作吗? 我已经查看了相等性,但我不确定如何使用该功能,我也无法在搜索中找到任何内容:( 【参考方案1】:

您还需要小心创建 DataFrame 的副本,否则 csvdata_old 将使用 csvdata 更新(因为它指向同一个对象):

csvdata_old = csvdata.copy()

查看是否相等,可以use assert_frame_equal as in this answer:

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

讨论了更好的方法...

【讨论】:

由于某种原因我得到了异常:Exception: Can only compare identically-labeled DataFrame objects 那给了你答案,对吧?这是说标签(行和列名称/值)不相同,因此 DataFrames 不能相同。在 Andy 的包装器中添加另一个 except 行:except Exception: return False @Hyflex 是的,正如 Tom 指出的那样,只需删除 AssertionError (在它仅在 AssertionError 上停止并引发其他任何事情之前)... 好的,我修复了标签(没有意识到我必须重新排序 csvdat_old 的标签顺序,我尝试将其合并到我的实际数据中,但即使数据相同时它也会更新输出,有没有办法找到/查看究竟是什么“不同”? 如何获取这些帧中的不同值?【参考方案2】:

这会比较两个数据框的,注意表之间的行/列数需要相同

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

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

【讨论】:

这里的主要好处是您可以使用 np.where 返回的索引位置来确定表格不匹配的确切位置并提醒用户该位置。【参考方案3】:

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

【讨论】:

不,从未存在过,它的工作原理也一样好。 (更好,因为它是单行而不是 5 行 它在花车上是如何工作的?我希望有一个精度参数。 肯定有比这更好的东西。只是一个错误不是一个令人满意的答案 不确定这是否是大多数人想要的。DataFrame.equals 进行了非常深入的比较。例如.. 我有 2 个值相等的数据帧.. 但事实证明 DataFrames 也有一些参数称为 Axis 1IntBlockObjectBlock。这些在pd._data 下定义。如果这两个对象之间的这些不相同..它将导致 False @Nickpick DataFrame.eq 可能很适合定位不相等的元素?【参考方案4】:

检查使用: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

【讨论】:

有一个问题:index.names 没有进行比较。详情见我的回答:***.com/a/43420842/304209【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

【讨论】:

这是我真正在寻找的答案。非常感谢 这太棒了!但我可以问它怎么能不忽略数据类型?例如,如果source_df 上有一个值4new_df 上的4.0,它仍然应该返回一个dataframe,因为这意味着存在差异,谢谢! 谢谢你。而且实用功能真的好用!【参考方案7】:

就我而言,我遇到了一个奇怪的错误,即使索引、列名 并且值相同,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 中的语句。

TL;DR

效果很好的是

all(final_df1 == final_df2).

这会逐个元素进行比较,同时忽略不包含的参数 比较重要。

TL;DR2

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

【讨论】:

有谁知道为什么从 CSV 读取的数据框与从 Excel 工作簿读取的数据框显示不同,即使它们相同?【参考方案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'],
)

将产生:

注意:在 pandas 的下一个版本之前,为避免将来如何设置 sort 参数的警告,只需添加 sort=False 参数即可。如下:

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

【讨论】:

【参考方案9】:

希望下面的sn-p代码对你有帮助!

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

【讨论】:

以上是关于比较两个熊猫数据框的差异的主要内容,如果未能解决你的问题,请参考以下文章

两个熊猫数据框的联合

具有两个以上数据框的熊猫的外部合并[重复]

如何在熊猫数据框的每一行中找到选定列中的两个最低值?

熊猫数据框:在进行涉及两个数据框的算术运算时如何在多个索引级别上进行匹配

查找熊猫中两个日期之间差异的最简单方法

熊猫数据框的视觉探索[关闭]