比较两个pandas数据帧的差异

时间:2013-11-11 22:50:02

标签: python python-2.7 pandas

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

有什么想法吗?

9 个答案:

答案 0 :(得分:43)

您还需要小心创建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

讨论了更好的方法......

答案 1 :(得分:11)

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

答案 2 :(得分:7)

使用以下方式检查: 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

答案 3 :(得分: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)

答案 4 :(得分: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]))

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

答案 5 :(得分: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 :(得分:1)

在我的情况下,我遇到了一个奇怪的错误,即即使索引,列名 和值相同,DataFrames不匹配。我一直追踪到 数据类型,似乎pandas有时可以使用不同的数据类型, 导致此类问题

例如:

param2 = pd.DataFrame({'a': [1]}) param1 = pd.DataFrame({'a': [1], 'b': [2], 'c': [2], 'step': ['alpha']})

如果您选中param1.dtypesparam2.dtypes,则会发现'a'是 为object输入param1,为int64输入param2。现在,如果你这样做 使用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来检查数据框的其余元素。

答案 7 :(得分:1)

拉出对称差异:

# define universe of possible input values
alphabet = 'abcdefghijklmnopqrstuvwxyz'

# define a mapping of chars to integers
char_to_int = dict((c, i) for i, c in enumerate(alphabet))
int_to_char = dict((i, c) for i, c in enumerate(alphabet))


def one_hot_encode(data_array):
    integer_encoded = [char_to_int[char] for char in data_array]

    # one hot encode
    onehot_encoded = list()
    for value in integer_encoded:
        letter = [0 for _ in range(len(alphabet))]
        letter[value] = 1
        onehot_encoded.append(letter)

    return onehot_encoded

例如:

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

将产生产量:

enter image description here

注意:在下一个熊猫发布之前,为避免出现有关将来将如何设置sort参数的警告,只需添加df1 = pd.DataFrame({ 'num': [1, 4, 3], 'name': ['a', 'b', 'c'], }) df2 = pd.DataFrame({ 'num': [1, 2, 3], 'name': ['a', 'b', 'd'], }) 参数。如下:

sort=False

答案 8 :(得分:0)

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

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